cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

How to get nodes with a certain property at path length = 1 and also, separately, >1

graphene
Node Clone

Let's say I have a graph with User nodes and Friendship nodes, and Users can have SENT_REQUEST and RECEIVED_REQUEST relationships to Friendship nodes. Users are connected to each other through Friendship nodes. Friendship nodes have a createdAt property, which is a dateTime() timestamp.

I want to make a query that will find out if:
1) the root user has any Friendships that have a createdAt time from today, and
2) any Users reachable from the root User have any Friendships that have a createdAt time from today

I tried doing this with multiple match clauses, but it doesn't work, I think because it won't re-use the outgoing SENT_REQUEST relationships from the root user to its Friendship nodes from the first MATCH clause in the second MATCH clause. 
Here's my query that doesn't work (if the root user does not have a friendship created today but one of its friends does, it returns `false` for both.) If I split it into two queries, they each work on their own, so I think the logic of each MATCH clause is fine in itself, but putting them together breaks it. 
How can this be improved?

MATCH (u:User {userId: "4567"})-[]-(f:Friendship)
WHERE datetime() + duration.between(datetime(f.createdAt), datetime()) < datetime() + duration("P1D")
MATCH p=(u)-[r*]-(f2:Friendship)
WHERE datetime() + duration.between(datetime(f2.createdAt), datetime()) < datetime() + duration("P1D")
RETURN count(DISTINCT f) > 0 as userFriendshipToday, count(DISTINCT f2) > 0 as networkFriendshipToday

 

1 ACCEPTED SOLUTION

The cause of your result for the scenario is because once the first match has no result the second one is not executed. Typically you would not get any results back. In your case, you do get a result back because you are returning values that are both functions of counts. Both are false because neither matched, so each collection is empty. 

Extracting out the match for the user, will allow it to be used for each match. Also, using optional match will allow the query to continue if a match is not found. The following should fix your issue. 

In the query, I moved the calculation of userFriendshipToday up in the query before the second optional match.  This avoids a Cartesian product between the to match results. 

MATCH (u:User {userId: "4567"})
OPTIONAL MATCH (u)-[]-(f:Friendship)
WHERE duration.between(datetime(f.createdAt), datetime()) < duration("P1D")
WITH u, count(DISTINCT f) > 0 as userFriendshipToday
OPTIONAL MATCH (u)-[*]-(f2:Friendship)
WHERE duration.between(datetime(f2.createdAt), datetime()) < duration("P1D")
RETURN userFriendshipToday, count(DISTINCT f2) > 0 as networkFriendshipToday

Note: I don't think you need to add datetime() in your inequalities, as you have it on both sides of the inequality, so it can be removed from both sides of the inequality without affecting the inequality. 

View solution in original post

2 REPLIES 2

The cause of your result for the scenario is because once the first match has no result the second one is not executed. Typically you would not get any results back. In your case, you do get a result back because you are returning values that are both functions of counts. Both are false because neither matched, so each collection is empty. 

Extracting out the match for the user, will allow it to be used for each match. Also, using optional match will allow the query to continue if a match is not found. The following should fix your issue. 

In the query, I moved the calculation of userFriendshipToday up in the query before the second optional match.  This avoids a Cartesian product between the to match results. 

MATCH (u:User {userId: "4567"})
OPTIONAL MATCH (u)-[]-(f:Friendship)
WHERE duration.between(datetime(f.createdAt), datetime()) < duration("P1D")
WITH u, count(DISTINCT f) > 0 as userFriendshipToday
OPTIONAL MATCH (u)-[*]-(f2:Friendship)
WHERE duration.between(datetime(f2.createdAt), datetime()) < duration("P1D")
RETURN userFriendshipToday, count(DISTINCT f2) > 0 as networkFriendshipToday

Note: I don't think you need to add datetime() in your inequalities, as you have it on both sides of the inequality, so it can be removed from both sides of the inequality without affecting the inequality. 

graphene
Node Clone

Thank you! I forgot about OPTIONAL MATCH