似乎Neo4j故意省略了循环,所以查询如下:
MATCH (n1)-[:R]->(n2)<-[:R]-(n1)
RETURN n1, n2;
除非在R
和n1
之间存在两种类型为n2
的关系,否则始终不会返回任何内容(这绝对可能且是一次糟糕的黑客攻击)。
但是我有一个场景,这个周期可能会发生并且是理想的:
MATCH (n1)-[:R]->(n2)<-[:R]-(n3)
RETURN n1, n2, n3;
在此查询中,n1
和n3
可能是相同的节点或不同的节点,它们都取决于数据(两者都有效)。实现此目的的一种方法是:
MATCH (n1)-[:R]->(n2)
MATCH (n2)<-[:R]-(n3)
RETURN n1, n2, n3;
这最后一个查询将包括所有路径甚至周期,它完全没问题。但我的情况甚至比这更复杂:
MATCH (n0)
OPTIONAL MATCH (n0)-[:R0]->(n1)-[:R]->(n2)<-[:R]-(n3)
RETURN n0, n1, n2, n3;
正如我们之前所见,在此查询中省略了周期,因此我们必须将其分解为两个OPTIONAL MATCH
es:
MATCH (n0)
OPTIONAL MATCH (n0)-[:R0]->(n1)-[:R]->(n2)
OPTIONAL MATCH (n2)<-[:R]-(n3)
RETURN n0, n1, n2, n3;
但这与以前不一样(如果另一个有效)。这里第二个OPTIONAL MATCH
可能不会返回任何路径,而第一个路径。换句话说,两个OPTIONAL MATCH
es是独立的。
所以我的问题是:如何实现以下查询并获得结果中的循环?
MATCH (n0)
OPTIONAL MATCH (n0)-[:R0]->(n1)-[:R]->(n2)<-[:R]-(n3)
RETURN n0, n1, n2, n3;
我希望它不会太混乱!
为什么两个OPTIONAL MATCH
不是答案
考虑以下节点和关系:
CREATE (n0:S)-[:R]->(n1:R)<-[:R]-(n2:E)-[:R]->(n3:R:L);
CREATE (n0:S)-[:R]->(n1:R:L)<-[:R]-(n2:E);
CREATE (n0:S)-[:R]->(n1:R)<-[:R]-(n2:E);
在上面的示例中,以下是标签的含义(因此您可以与问题相关):
:S
开始节点:R
修订:E
实体:L
最新版本在此示例中,每个数据记录都在:E
+ :R
中表示,当记录更新时,会向其添加新的:R
。数据的当前状态标记为:L
,因此我们可以找到最新版本。
现在,在给出的三个示例中,最后一个是无效数据,因为它没有任何:L
。第一个有两个版本,第二个有一个。
请求的查询应该:
:S
如果Neo4j支持循环,此查询将返回请求的数据:
MATCH (n1:S)
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)-[:R]->(n4:R:L)
RETURN labels(n1), labels(n3), labels(n4);
上述查询的预期结果为:
╒════════════╤════════════╤════════════╕
│"labels(n1)"│"labels(n3)"│"labels(n4)"│
╞════════════╪════════════╪════════════╡
│["S"] │["E"] │["R","L"] │
├────────────┼────────────┼────────────┤
│["S"] │["E"] │["R","L"] │
├────────────┼────────────┼────────────┤
│["S"] │null │null │
└────────────┴────────────┴────────────┘
但实际结果是:
╒════════════╤════════════╤════════════╕
│"labels(n1)"│"labels(n3)"│"labels(n4)"│
╞════════════╪════════════╪════════════╡
│["S"] │["E"] │["R","L"] │
├────────────┼────────────┼────────────┤
│["S"] │null │null │
├────────────┼────────────┼────────────┤
│["S"] │null │null │
└────────────┴────────────┴────────────┘
正如您所看到的那样,第二条路径被缩短了,因为它包含了一个循环。现在,如果我们使用两个OPTIONAL MATCH
方法:
MATCH (n1:S)
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)
OPTIONAL MATCH (n3)-[:R]->(n4:R:L)
RETURN labels(n1), labels(n3), labels(n4);
结果将是:
╒════════════╤════════════╤════════════╕
│"labels(n1)"│"labels(n3)"│"labels(n4)"│
╞════════════╪════════════╪════════════╡
│["S"] │["E"] │["R","L"] │
├────────────┼────────────┼────────────┤
│["S"] │["E"] │["R","L"] │
├────────────┼────────────┼────────────┤
│["S"] │["E"] │null │
└────────────┴────────────┴────────────┘
虽然第二种情况是固定的,但第三种情况现在是问题,那是因为两个可选条款可以独立存在。
很抱歉这个问题很长,我试着简短一点!
答案 0 :(得分:1)
[增订]
(A)基于新问题的新答案。
MATCH (s:S)-[:R]->(firstRev:R)
OPTIONAL MATCH (firstRev)<-[:R]-(e:E)
OPTIONAL MATCH (e)-[:R]->(latestRev:L)
RETURN
LABELS(s) AS ls,
CASE WHEN latestRev IS NOT NULL THEN LABELS(e) END AS le,
LABELS(latestRev) AS ll;
上述查询使用2个OPTIONAL MATCH
子句来允许循环(其中2 R
个关系相同)。如果第二个CASE
失败,le
子句将返回NULL OPTIONAL MATCH
值。
(B)原始答案(已废弃)
这对你有用吗?
OPTIONAL MATCH (n1)-[:R]->(n2)
OPTIONAL MATCH (n2)<-[:R]-(n3)
RETURN n1, n2, n3;
答案 1 :(得分:1)
1)您可以使用两个“选项”更正版本,并添加对节点匹配的检查:
MATCH (n1:S)
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)
OPTIONAL MATCH (n3t)-[:R]->(n4:R:L) WHERE n3t = n3
RETURN labels(n1), labels(n3t), labels(n4);
2)我认为你使用术语cycle
是错误的,这会让你觉得你对数据模型有些不对劲。在您的测试数据上没有周期:
答案 2 :(得分:1)
如果我正确理解了这个问题,这个查询应该会为您提供您正在寻找的预期结果表:
MATCH (n1:S)
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)
WHERE (n3)-[:R]->(:R:L)
OPTIONAL MATCH (n3)-[:R]->(n4:R:L)
RETURN labels(n1), labels(n3), labels(n4)
关键是我们给第一个可选匹配的WHERE。只有当n3
具有到:R:L
节点的所需路径时,OPTIONAL MATCH才会匹配,并且它将计算已被OPTIONAL MATCH遍历的关系和节点。