Reputation: 527
I'm trying to find all nodes that don't connect to a specific node. I have an app where students doing an assignment discover themes in a story, and then write explications. Then, other students do peer reviews of these explications. My data looks like this:
Assignment-hasTheme->Theme-hasChild->Theme
Annotation-theme->Theme
Explication-owner->User
Explication-annotation->Annotation
PeerReview-explication->Explication
As part of the application, when a user has to do a peer review, I have to find all the explications written by other users. It seems to me like this query should work:
MATCH
(u),
(a)-[:hasTheme]->(:Theme)
-[:hasChild*]->(:Theme)
<-[:theme]-(ann:Annotation)
<-[:annotation]-(e:Explication)
OPTIONAL MATCH
(e)<-[:explication]-(p:PeerReview)
WHERE id(a)=7 AND id(u)=4
AND (e)-[:owner]->(u)
RETURN e, count(e) AS explicationCount
ORDER BY explicationCount ASC
The problem is that it doesn't: I get all the explications that all users have written. That includes the explications the user wrote. Can anyone tell me how to exclude those?
Upvotes: 1
Views: 237
Reputation: 30417
The problem is that the WHERE
clause is only associated with one other clause...the preceding MATCH
, OPTIONAL MATCH
, or WITH
. In your query, it's associated with the OPTIONAL MATCH
.
If you re-read your query knowing this, you can see that the first MATCH
has no WHERE
clause, so it's matching on all assignments and all users, finding all explications.
THEN it does the optional match to get :PeerReviews
matching on the given assignment and user ids where the explication owner is the user with the given id. The WHERE
is only affecting which :PeerReviews
(variable p
) are matched.
A couple other things I can see...you're introducing a variable ann
on the :Annotations
matched in the pattern, and a variable p
for the :PeerReview
, but you're not actually doing anything with these in the query. This also makes your OPTIONAL MATCH
useless, you're not returning or operating on the matched :PeerReviews
.
My recommendation is to remove those variables and remove your OPTIONAL MATCH
completely.
MATCH
(u),
(a)-[:hasTheme]->(:Theme)
-[:hasChild*]->(:Theme)
<-[:theme]-(:Annotation)
<-[:annotation]-(e:Explication)
WHERE id(a)=7 AND id(u)=4
AND (e)-[:owner]->(u)
RETURN e, count(e) AS explicationCount
ORDER BY explicationCount ASC
If you do want to add in the OPTIONAL MATCH
and use the matched :PeerReview
, ensure that it's below the WHERE
affecting the MATCH
, like so:
MATCH
(u),
(a)-[:hasTheme]->(:Theme)
-[:hasChild*]->(:Theme)
<-[:theme]-(:Annotation)
<-[:annotation]-(e:Explication)
WHERE id(a)=7 AND id(u)=4
AND (e)-[:owner]->(u)
OPTIONAL MATCH
(e)<-[:explication]-(p:PeerReview)
RETURN e, count(e) AS explicationCount, p
ORDER BY explicationCount ASC
EDIT
In response to the comments where the desired result is each :Explication and the count of all linked :PeerReviews, you would use this query:
MATCH
(u),
(a)-[:hasTheme]->(:Theme)
-[:hasChild*0..]->(:Theme)
<-[:theme]-(:Annotation)
<-[:annotation]-(e:Explication)
WHERE id(a)=7 AND id(u)=4
AND (e)-[:owner]->(u)
OPTIONAL MATCH
(e)<-[:explication]-(p:PeerReview)
RETURN e, count(p) as peerReviewCount
ORDER BY peerReviewCount ASC
EDIT
Updated the above query so it will find annotations on the parent theme as well instead of just its children.
Upvotes: 2