Cypher query to find nodes that are not related to other node by property

拈花ヽ惹草 提交于 2019-12-24 16:53:16

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!