我正在尝试编写一个Cypher查询,它是一种“联盟”查询,基本上是这样的:
MATCH (myNodeUsedInAllSubQueries)
WITH myNodeUsedInAllSubQueries
MATCH (a)-[...]->(myNodeUsedInAllSubQueries)
RETURN a
UNION
MATCH (b)-[...]->(myNodeUsedInAllSubQueries)
RETURN b
...
我想首先匹配(myNodeUsedInAllSubQueries)
一次,因为此节点在所有子查询中都使用。
当然,在我的示例中,此节点的检索不仅如此简单(它涉及关系和一个WHERE
子句,但在这里我将使其保持简单)。
我将尝试通过一个简单的示例以及到目前为止我已经尝试过的内容进行解释。
在图形上,图形结构如下:
(John: Person) ----------[LIKES]----------> (pizza: Food)
^
(Developers: Group) ------[LIKES]------┘
(Jim: Person) --[BELONGS_TO]--> (Business: Group) --[LIKES]--> (apple: Food)
该示例可访问here in Neo4J console。导入脚本在这里(如果您想在本地重现问题):
CREATE (john: Person{name: "John"});
CREATE (jim: Person{name: "Jim"});
CREATE (devs: Group{name: "Developers"});
CREATE (business: Group{name: "Business"});
CREATE (pizza: Food{name: "pizza"});
CREATE (apple: Food{name: "apple"});
MATCH (john: Person{name: "John"}), (pizza: Food{name: "pizza"})
CREATE (john)-[:LIKES]->(pizza);
MATCH (jim: Person{name: "Jim"}), (business: Group{name: "Business"})
CREATE (jim)-[:BELONGS_TO]->(business);
MATCH (devs: Group{name: "Developers"}), (pizza: Food{name: "pizza"})
CREATE (devs)-[:LIKES]->(pizza);
MATCH (business: Group{name: "Business"}), (apple: Food{name: "apple"})
CREATE (business)-[:LIKES]->(apple);
对于该特定示例,我的问题是:如何检索所有喜欢披萨的Person
节点?知道这一点:
Person
可以喜欢Food
(直接关系)Group
可以喜欢Food
,如果某人A
BELONGS_TO
是一个团体,则可以传递,
他LIKES
也是LIKES
团伙的食物(但没有直接关系
在这种情况下,Person
和Food
之间)我也想一次检索pizza
节点。正如我在简介中所述,在我的真实示例中,pizza
的检索可能非常复杂,因此我不想在每种情况下都复制MATCH
。
UNION
MATCH (pizza: Food{name: "pizza"})
WITH pizza
MATCH (p: Person)-[:LIKES]->(pizza)
RETURN p
UNION
MATCH (p: Person)-[:BELONGS_TO]->(g: Group)-[:LIKES]->(pizza)
RETURN p
此查询令人惊讶地返回2个节点:John
和Jim
。经过调查,我了解到
这是因为第二个(pizza)
子句中的UNION
并不指向pizza
节点
由第一个MATCH
(而不是任何节点)返回。我们可以通过运行来确认:
MATCH (pizza: Food{name: "pizza"})
WITH pizza
MATCH (p: Person)-[:LIKES]->(pizza)
RETURN p
UNION
MATCH (p: Person)-[:BELONGS_TO]->(g: Group)-[:LIKES]->(anything)
WHERE anything = pizza
RETURN p
这将返回错误:
Neo.ClientError.Statement.SyntaxError: Variable `pizza` not defined (line 7, column 18 (offset: 184))
"WHERE anything = pizza"
,验证pizza
节点未传播到第二个MATCH
的事实。
WITH
和COLLECT
这解决了pizza
节点无法从第一个MATCH
传递到第三个MATCH
的问题。
MATCH (pizza: Food{name: "pizza"})
WITH pizza
MATCH (p: Person)-[:LIKES]->(pizza)
WITH pizza, COLLECT(p) AS people
MATCH (p: Person)-[:BELONGS_TO]->(g: Group)-[:LIKES]->(pizza)
RETURN people + COLLECT(p) AS people
但是此查询不返回任何内容:这是因为第三个MATCH
不返回任何内容
(在Person
Group
中,LIKES
中没有pizza
)。
如果我在Person
Developers
中添加Group
:
MATCH (devs: Group{name: "Developers"})
CREATE (emma: Person{name: "Emma"})-[:BELONGS_TO]->(devs)
上一个查询成功返回John和Emma,因为最后一个MATCH
返回至少一个Person
。
但就我而言,这个MATCH
可能不返回任何内容,因此不起作用。
我希望这个例子简单明了。在这种情况下,我要查找的查询应该仅返回John,因为他是这里唯一喜欢Person
的{{1}}。
答案 0 :(得分:1)
[已更新]
这应该适用于您的简单用例:
MATCH (p:Person)-[:BELONGS_TO|LIKES*..2]->(food:Food {name:"pizza"})
RETURN food, COLLECT(p) AS people;
答案 1 :(得分:1)
作为Cybersam答案的替代方法,如果您的图形结构无法使MATCH (p:Person)-[:BELONGS_TO|LIKES*..2]->(food:Food)
有效(例如,如果您正在制作人们可以彼此喜欢的图形,并且您不想要返回一个喜欢另一个喜欢披萨的人(将遵循您的模式),您可以使用0..1
长度关系来表示该模式中的可选步骤:
MATCH (p:Person)-[:BELONGS_TO*0..1]->()-[:LIKES]->(food:Food)
WHERE food.name = "pizza"
RETURN COLLECT(p) AS people;
这允许同时匹配这两种模式:
(p:Person)-[:LIKES]->(food:Food)
和
(p:Person)-[:BELONGS_TO]->()-[:LIKES]->(food:Food)
我已经用这种方法写了knowledge base article。