'Given a graph depicting a social network where anyone can also post Write a query that finds all of Dani's friends up to level 3 who also marked likes

Given a graph depicting a social network where anyone can also post.

A user can be a friend of people or just like his post.

  • Types of relationships are: friend, likes, publish

  • Types of vertices: person, post

  • A person has the following data: name, age, gender

  • Post has the following data: title, date, content

Write a query that finds all of Dani's friends up to level 3 who also marked likes on all the posts he wrote and are older than him

Attempt:

MATCH (c:person) with COLLECT(c) AS persons 
MATCH (s:friend {name:"Dani"}) WHERE ALL (x IN persons WHERE (s)-[:friend*1..3]) 
and c.age > dani.age

I have wrong with the syntax I tried to search on google how to make double matches and I struggle with that, the hardest for me that to match all the friends who make likes to all posts of Dani published like the question asks to.

Thanks.



Solution 1:[1]

Welcome Epsilon 1! EDIT: support case where Dani did not publish anything:

You can do something like this:

MATCH (d:person{name:'Dani'})-[:friend*..3]-(friend:person)
WHERE friend.age > d.age
WITH d, collect(friend) AS friends
OPTIONAL MATCH (d)-[:publish]->(p:post)
WITH COUNT(p) AS countP, d, friends
OPTIONAL MATCH (d)-[:publish]->(:post)<-[:likes]-(lp:person)
WITH DISTINCT(lp) AS likePeople, COUNT(lp) AS likesCount, d, countP, friends
WHERE likesCount=countP AND (likePeople IN friends OR likePeople IS NULL)
RETURN CASE WHEN likePeople IS NOT NULL THEN likePeople ELSE friends END AS friends

Which using this sample data:

MERGE (a:person{name: 'Dani', age: 12})
MERGE (b:person{name: 'B', age: 13})
MERGE (c:person{name: 'C', age: 11})
MERGE (d:person{name: 'D', age: 13})
MERGE (e:person{name: 'E', age: 13})
MERGE (f:post{key: 2})
MERGE (g:post{key: 3})
MERGE (h:post{key: 4})
MERGE (i:person{name: 'I', age: 13})
MERGE (j:person{name: 'J', age: 13})
MERGE (k:post{key: 7})
MERGE (l:post{key: 8})
MERGE (m:post{key: 9})


MERGE (a)-[:publish]-(f)
MERGE (a)-[:publish]-(g)
MERGE (a)-[:publish]-(h)
MERGE (b)-[:publish]-(k)
MERGE (b)-[:publish]-(l)
MERGE (d)-[:publish]-(m)
MERGE (e)-[:likes]-(f)
MERGE (e)-[:likes]-(g)
MERGE (e)-[:likes]-(h)
MERGE (d)-[:likes]-(f)
MERGE (c)-[:likes]-(g)
MERGE (d)-[:likes]-(h)
MERGE (e)-[:likes]-(h)
MERGE (j)-[:likes]-(f)
MERGE (j)-[:likes]-(g)
MERGE (j)-[:likes]-(h)
MERGE (a)-[:friend]-(b)
MERGE (b)-[:friend]-(c)
MERGE (c)-[:friend]-(d)
MERGE (d)-[:friend]-(e)
MERGE (d)-[:friend]-(a)
MERGE (i)-[:friend]-(j)
MERGE (i)-[:friend]-(c)

Will return:

???????????????????????
?"friend"             ?
???????????????????????
?{"name":"E","age":13}?
???????????????????????

First we count the number of posts published by Dani, then we find all the persons who liked some of it and keep only the persons who liked the number of posts that we found on the first step (countP). Then we find all the friends with distance up to three and keep only these that are on our list from previous step (likePeople) and their age is larger than Dani's.

The WITH between the MATCH steps allows the query to keep using former results.

Edit: I updated the answer to support the case where Dani did not publish anything. In this case the results will be all of his friends up to 3 levels, that are older than him. This edge case allows me to explain the essence of OPTIONAL MATCH. When removing the OPTIONAL the query will return no friends, as it will find nothing on the second MATCH. If you do want to support the case of Dani not publishing, the OPTIONAL allows to continue the query with null where there are no results, which on our case, allow us to return friends.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1