Reputation: 1115
Neo4j documentation gives the following example:
CREATE (adam:User { name: 'Adam' }),(pernilla:User { name: 'Pernilla' }),
(david:User { name: 'David' }), (adam)-[:FRIEND]->(pernilla),
(pernilla)-[:FRIEND]->(david)
and
MATCH (user:User { name: 'Adam' })-[r1:FRIEND]-(friend)
MATCH (friend)-[r2:FRIEND]-(friend_of_a_friend)
RETURN friend_of_a_friend.name AS fofName
returns
+---------+
| fofName |
+---------+
| "David" |
| "Adam" |
+---------+
2 rows
I understand why David is returned, but I don't understand why Adam is returned. Adam is not a friend-of-friend. I appreciate an explanation.
Upvotes: 1
Views: 707
Reputation: 11216
It is because the second MATCH
does not have a direction
MATCH (friend)-[r2:FRIEND]-(friend_of_a_friend)
So from pernilla it matches -[:FRIEND]-
in both directions which, although it matches David, it also brings you back to Adam.
If you add an direction to the second MATCH
as below it should only return David. Although Pernilla has two FRIEND
relationships, one is inbound (from Adam) and the other is outbound (to David).
MATCH (user:User { name: 'Adam' })-[r1:FRIEND]-(friend)
MATCH (friend)-[r2:FRIEND]->(friend_of_a_friend)
RETURN friend_of_a_friend.name AS fofName
Upvotes: 3
Reputation: 510
this is the something that proves that proper understanding of what pattern means is necessary to form queries which gives the right and expected results .
A pattern can be a single node or a relation or a path.
when you did this
MATCH (user:User { name: 'Adam' })-[r1:FRIEND]-(friend)
you are looking for all the patterns i.e all friends of 'Adam' and catch here is the relation is not directed. And its supposed to be directionless since friend is bidirectional ..and when you did
MATCH (friend)-[r2:FRIEND]-(fof)
you are again looking for friends of a friend of 'Adam' and without directions.
And 'Adam' is a friend to a friend of him . That's why you see 'Adam' in the results .
To be more clear here , you are not looking for friends of friends of 'Adam'. you are looking for all the friends for any friend of 'Adam'. Hope , it helped
if you dont want to see 'Adam' , you can do any of the following,
MATCH (user:User { name: 'Adam' })-[r1:FRIEND]-(friend)-[r2:FRIEND]-(fof)
RETURN fof.name```
or this ,
MATCH (user:User { name: 'Adam' })-[r1:FRIEND*2]-(fof) RETURN fof.name
i would suggest going through this documentation of patterns https://neo4j.com/docs/cypher-manual/current/syntax/patterns/
Upvotes: 1
Reputation: 30417
You have two separate matches in your query. The first finds all friends of Adam, for which there's just one: Pernilla.
The second MATCH finds friends of that friend (Pernilla), and there are two nodes connected by :FRIEND relationships: Adam (this would traverse the relationship you originally used to get from Adam to Pernilla) and David.
If you instead used a single MATCH for this:
MATCH (user:User { name: 'Adam' })-[:FRIEND]-(friend)-[:FRIEND]-(friend_of_a_friend)
RETURN friend_of_a_friend.name AS fofName
or
MATCH (user:User { name: 'Adam' })-[:FRIEND]-(friend), (friend)-[:FRIEND]-(friend_of_a_friend)
RETURN friend_of_a_friend.name AS fofName
then you would only get back David as the friend of a friend. The reason is because of Cypher's uniqueness that per path in a MATCH, a relationship may only be traversed once. When there are two MATCHes though then there are no restrictions between relationships traversed between them.
This is illustrated in more depth in the Cypher documentation on uniqueness.
Upvotes: 1