goldfinger
goldfinger

Reputation: 1115

multiple matches in Cypher - Neo4j

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

Answers (3)

Dave Bennett
Dave Bennett

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

TheTeacher
TheTeacher

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

InverseFalcon
InverseFalcon

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

Related Questions