问题
Consider the following DB structure:
For your convenience, you can create it using:
create (p1:Person {name: "p1"}),(p2:Person {name: "p2"}),(p3:Person {name: "p3"}),(e1:Expertise {title: "Exp1"}),(e2:Expertise {title: "Exp2"}),(e3:Expertise {title: "Exp3"}),(p1)-[r1:Expert]->(e1),(p1)-[r2:Expert]->(e2),(p2)-[r3:Expert]->(e2),(p3)-[r4:Expert]->(e3),(p2)-[r5:Expert]->(e3)
I want to be able to find all Person
nodes that are not related to a specific Expertise
node, e.g. "Exp2"
I tried
MATCH (p:Person)--(e:Expertise)
WHERE NOT (e.title = "Exp2")
RETURN p
But it returns all the Person
nodes (while I expected it to return only p3
).
Logically, this result makes sense because each of these nodes is related to at least one Expertise
that is not Exp2
.
But what I want is to find all the Person
nodes that are not related to Exp2
, even if they are related to other nodes as well.
How can this be done?
Edit
It appears that I wasn't clear on the requirements. This is a (very) simplified way of presenting my problem with a much more complicated DB.
Consider the possibility that Expertise
has more properties which I would like to use in the same query (not necessarily with negation). For example:
MATCH (p)--(e)
WHERE e.someProp > 5 AND e.anotherProp = "cookie" AND NOT e.title = "Exp2"
回答1:
Little change query from @ChristopheWillemsen:
MATCH (e:Expertise) WHERE e.someProperty > 5 AND NOT e.title = someValue
WITH collect(e) as es
MATCH (p:Person) WHERE all(e in es WHERE NOT Exists( (p)--(e) ) )
RETURN p
UPDATE:
// Collect the `Expertise` for which the following conditions:
MATCH (e:Expertise) WHERE e.num > 3 AND e.title = 'Exp2'
WITH collect(e) as es
// Select the users who do not connect with any of of expertise from `es` set:
OPTIONAL MATCH (p:Person) WHERE all(e in es WHERE NOT Exists( (p)--(e) ) )
RETURN es, collect(p)
Another query with some optimization:
// Get the set of `Expertise-node` for which the following conditions:
MATCH (e:Expertise) WHERE e.num > 3 AND e.title = 'Exp2'
// Collect all `Person-node` connected to node from the `Expertise-node` set:
OPTIONAL MATCH (e)--(p:Person)
WITH collect(e) as es, collect(distinct id(p)) as eps
//Get all `Person-node` not in `eps` set:
OPTIONAL MATCH (p:Person) WHERE NOT id(p) IN eps
RETURN es, collect(p)
回答2:
UPDATE
You need to restrict it a bit more, meaning to only the person
MATCH (p:Person), (e:Expertise {title="Exp2"})
WHERE NOT (p)-[]->(e)
RETURN p
I think you will be just fine with the <>
operator :
MATCH (p:Person)--(e:Expertise)
WHERE e.title <> "Exp2"
RETURN p
Or you can express it in a pattern :
MATCH (p:Person)
WHERE NOT EXISTS((p)--(e:Expertise {title:"Exp2"}))
RETURN p
来源:https://stackoverflow.com/questions/37463790/cypher-query-to-find-nodes-that-are-not-related-to-other-node-by-property