从 apoc.do.when 返回条件 CASE WHEN 值的奇怪结果
Weird result returning conditional CASE WHEN value from apoc.do.when
我们有下图
其中灰色节点 (:Conversation) 代表用户之间的对话 (:User 粉红色节点)。我创建了查询,试图找到人与人之间的当前对话,如果不存在,则创建它。在这两种情况下,都必须返回对话。
这是它的代码:
MATCH (u1:User {login:"User_1"})
MATCH (u2:User {login:"User_2"})
MATCH (u3:User {login:"User_3"})
OPTIONAL MATCH
(conv:Conversation)-[:CONDUCTED_BY]->(u1),
(conv)-[:CONDUCTED_BY]->(u2),
(conv)-[:CONDUCTED_BY]->(u3)
WHERE NOT EXISTS {
MATCH (conv)-[:CONDUCTED_BY]->(u:User)
WHERE NOT u IN [u1, u2, u3]
}
CALL apoc.do.when(conv IS NULL,
"WITH $u1 AS u1, $u2 AS u2, $u3 AS u3 " +
"CREATE (conv:Conversation) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u1) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u2) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u3) " +
"RETURN conv AS conv",
"RETURN $conv AS conv", {u1:u1, u2:u2, u3:u3, conv:conv}) YIELD value
[...WEIRD PART...]
解释:
可选匹配 - 尝试查找用户 1、2、3 之间的当前对话 - 对话 71 和 72
WHERE NOT EXIST - 排除这些用户之间可能包含其他人的其他对话,例如 User_4 - 72
我们最终只有一个我们感兴趣的对话:71
...现在奇怪的部分出现在 [...WEIRD PART...]
如果我们用代码
替换[...WEIRD PART...]
RETURN value.conv
一切都很好,但在我想出这个解决方案之前,我一直在努力处理其他代码,在 apoc 映射中 conv:conv 没有被包含并且 else-query 只是 ""
WITH CASE WHEN conv IS NULL THEN value ELSE conv END AS conv
RETURN conv
那部分是在我们每次 运行 查询时在这些用户 1、2、3 之间创建新对话。
但是,如果我将其替换为
RETURN value
它工作正常,我的意思是它没有在用户 1、2、3 之间创建新对话(如果存在)。
问题:我不明白为什么下面的代码
MATCH (u1:User {login:"User_1"})
MATCH (u2:User {login:"User_2"})
MATCH (u3:User {login:"User_3"})
OPTIONAL MATCH
(conv:Conversation)-[:CONDUCTED_BY]->(u1),
(conv)-[:CONDUCTED_BY]->(u2),
(conv)-[:CONDUCTED_BY]->(u3)
WHERE NOT EXISTS {
MATCH (conv)-[:CONDUCTED_BY]->(u:User)
WHERE NOT u IN [u1, u2, u3]
}
CALL apoc.do.when(conv IS NULL,
"WITH $u1 AS u1, $u2 AS u2, $u3 AS u3 " +
"CREATE (conv:Conversation) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u1) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u2) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u3) " +
"RETURN conv",
"", {u1:u1, u2:u2, u3:u3}) YIELD value
WITH CASE WHEN conv IS NULL THEN value ELSE conv END AS conv
RETURN conv
可能对这种奇怪的行为负责。
感谢您的澄清,我可以重现这个,这绝对不是预期的。这对我来说像是一个错误。
我们可以通过将您的 CASE 中使用的别名重命名为 conv2
或 conv
以外的任何别名来规避此问题。这应该有效:
MATCH (u1:User {login:"User_1"})
MATCH (u2:User {login:"User_2"})
MATCH (u3:User {login:"User_3"})
OPTIONAL MATCH
(conv:Conversation)-[:CONDUCTED_BY]->(u1),
(conv)-[:CONDUCTED_BY]->(u2),
(conv)-[:CONDUCTED_BY]->(u3)
WHERE NOT EXISTS {
MATCH (conv)-[:CONDUCTED_BY]->(u:User)
WHERE NOT u IN [u1, u2, u3]
}
CALL apoc.do.when(conv IS NULL,
"WITH $u1 AS u1, $u2 AS u2, $u3 AS u3 " +
"CREATE (conv:Conversation) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u1) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u2) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u3) " +
"RETURN conv",
"", {u1:u1, u2:u2, u3:u3}) YIELD value
WITH CASE WHEN conv IS NULL THEN value ELSE conv END AS conv2
RETURN conv2
我会向我们的工程师提出这个问题以确认并开始修复错误。
这是存在子查询名称间距的错误。由于 conv
被重用以表示其他含义,因此 Cypher 将除最后两个 conv
之外的所有内容重写为 conv@x
,将最后两个重写为 conv@y
,以便区分它们。这里的 x 和 y 是具有特定含义的 conv
第一次出现的位置。此重写未正确传播到内部子查询。
已在此处修复:https://github.com/neo4j/neo4j/commit/2890463ad6d2f323bfbad5cf453f14b42f51c830并将包含在 Neo4j 4.0 的下一个补丁版本中。
我们有下图
其中灰色节点 (:Conversation) 代表用户之间的对话 (:User 粉红色节点)。我创建了查询,试图找到人与人之间的当前对话,如果不存在,则创建它。在这两种情况下,都必须返回对话。 这是它的代码:
MATCH (u1:User {login:"User_1"})
MATCH (u2:User {login:"User_2"})
MATCH (u3:User {login:"User_3"})
OPTIONAL MATCH
(conv:Conversation)-[:CONDUCTED_BY]->(u1),
(conv)-[:CONDUCTED_BY]->(u2),
(conv)-[:CONDUCTED_BY]->(u3)
WHERE NOT EXISTS {
MATCH (conv)-[:CONDUCTED_BY]->(u:User)
WHERE NOT u IN [u1, u2, u3]
}
CALL apoc.do.when(conv IS NULL,
"WITH $u1 AS u1, $u2 AS u2, $u3 AS u3 " +
"CREATE (conv:Conversation) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u1) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u2) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u3) " +
"RETURN conv AS conv",
"RETURN $conv AS conv", {u1:u1, u2:u2, u3:u3, conv:conv}) YIELD value
[...WEIRD PART...]
解释:
可选匹配 - 尝试查找用户 1、2、3 之间的当前对话 - 对话 71 和 72
WHERE NOT EXIST - 排除这些用户之间可能包含其他人的其他对话,例如 User_4 - 72
我们最终只有一个我们感兴趣的对话:71
...现在奇怪的部分出现在 [...WEIRD PART...]
如果我们用代码
替换[...WEIRD PART...]RETURN value.conv
一切都很好,但在我想出这个解决方案之前,我一直在努力处理其他代码,在 apoc 映射中 conv:conv 没有被包含并且 else-query 只是 ""
WITH CASE WHEN conv IS NULL THEN value ELSE conv END AS conv
RETURN conv
那部分是在我们每次 运行 查询时在这些用户 1、2、3 之间创建新对话。 但是,如果我将其替换为
RETURN value
它工作正常,我的意思是它没有在用户 1、2、3 之间创建新对话(如果存在)。
问题:我不明白为什么下面的代码
MATCH (u1:User {login:"User_1"})
MATCH (u2:User {login:"User_2"})
MATCH (u3:User {login:"User_3"})
OPTIONAL MATCH
(conv:Conversation)-[:CONDUCTED_BY]->(u1),
(conv)-[:CONDUCTED_BY]->(u2),
(conv)-[:CONDUCTED_BY]->(u3)
WHERE NOT EXISTS {
MATCH (conv)-[:CONDUCTED_BY]->(u:User)
WHERE NOT u IN [u1, u2, u3]
}
CALL apoc.do.when(conv IS NULL,
"WITH $u1 AS u1, $u2 AS u2, $u3 AS u3 " +
"CREATE (conv:Conversation) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u1) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u2) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u3) " +
"RETURN conv",
"", {u1:u1, u2:u2, u3:u3}) YIELD value
WITH CASE WHEN conv IS NULL THEN value ELSE conv END AS conv
RETURN conv
可能对这种奇怪的行为负责。
感谢您的澄清,我可以重现这个,这绝对不是预期的。这对我来说像是一个错误。
我们可以通过将您的 CASE 中使用的别名重命名为 conv2
或 conv
以外的任何别名来规避此问题。这应该有效:
MATCH (u1:User {login:"User_1"})
MATCH (u2:User {login:"User_2"})
MATCH (u3:User {login:"User_3"})
OPTIONAL MATCH
(conv:Conversation)-[:CONDUCTED_BY]->(u1),
(conv)-[:CONDUCTED_BY]->(u2),
(conv)-[:CONDUCTED_BY]->(u3)
WHERE NOT EXISTS {
MATCH (conv)-[:CONDUCTED_BY]->(u:User)
WHERE NOT u IN [u1, u2, u3]
}
CALL apoc.do.when(conv IS NULL,
"WITH $u1 AS u1, $u2 AS u2, $u3 AS u3 " +
"CREATE (conv:Conversation) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u1) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u2) " +
"MERGE (conv)-[:CONDUCTED_BY]->(u3) " +
"RETURN conv",
"", {u1:u1, u2:u2, u3:u3}) YIELD value
WITH CASE WHEN conv IS NULL THEN value ELSE conv END AS conv2
RETURN conv2
我会向我们的工程师提出这个问题以确认并开始修复错误。
这是存在子查询名称间距的错误。由于 conv
被重用以表示其他含义,因此 Cypher 将除最后两个 conv
之外的所有内容重写为 conv@x
,将最后两个重写为 conv@y
,以便区分它们。这里的 x 和 y 是具有特定含义的 conv
第一次出现的位置。此重写未正确传播到内部子查询。
已在此处修复:https://github.com/neo4j/neo4j/commit/2890463ad6d2f323bfbad5cf453f14b42f51c830并将包含在 Neo4j 4.0 的下一个补丁版本中。