Cypher查询 - 可选创建

时间:2014-05-16 13:38:15

标签: neo4j cypher

我正在尝试创建一个类似社交网络的结构。 我想创建一个看起来像这样的帖子的时间表

(用户:人) - [:发布] - GT;(P1:POST) - [:PREV] - GT; [P2:POST] ...

我的问题如下。 假设用户的帖子已经存在,我可以通过执行以下密码查询来创建新帖子

MATCH (user:Person {id:#id})-[rel:POSTED]->(prev_post:POST)
DELETE rel
CREATE (user)-[:POSTED]->(post:POST {post:"#post", created:timestamp()}),
       (post)-[:PREV]->(prev_post);

假设用户尚未创建帖子,则此查询失败。所以我尝试在一个更新查询中以某种方式包含两种情况(用户没有帖子/用户至少有一个帖子)(我想在“发布时间轴”中插入新帖子)

MATCH (user:Person {id:"#id"})
OPTIONAL MATCH (user)-[rel:POSTED]->(prev_post:POST)
CREATE (post:POST {post:"#post2", created:timestamp()})
FOREACH (o IN CASE WHEN rel IS NOT NULL THEN [rel] ELSE [] END |
  DELETE rel
)
FOREACH (o IN CASE WHEN prev_post IS NOT NULL THEN [prev_post] ELSE [] END |
  CREATE (post)-[:PREV]->(o)
)
MERGE (user)-[:POSTED]->(post)

是否有任何类型的if语句(或某种类型的CREATE IF NOT NULL)以避免使用foreach循环两次(查询看起来有点复杂,我知道循环只运行一次)?

然而,这是唯一的解决方案,我可以在研究this SO post之后想出来。我读到in an older post没有if语句这样的东西。

编辑:问题是:将两个案例都包含在一个查询中甚至是好的,因为我知道“无案例”只会发生一次而所有其他案例都是“至少一个帖子”吗?

干杯

4 个答案:

答案 0 :(得分:2)

我也没有看到比使用FOREACH更好的解决方案。

但是,我认为我可以使您的查询更有效率。我的解决方案基本上将2 FOREACH个测试合并为1,因为prev_postrel必须同时是NULL或非NULL。它还结合了CREATEMERGE(无论如何都应该是CREATE

MATCH (user:Person {id:"#id"})
OPTIONAL MATCH (user)-[rel:POSTED]->(prev_post:POST)
CREATE (user)-[:POSTED]->(post:POST {post:"#post2", created:timestamp()})
FOREACH (o IN CASE WHEN prev_post IS NOT NULL THEN [prev_post] ELSE [] END |
  DELETE rel
  CREATE (post)-[:PREV]->(o)
)

答案 1 :(得分:2)

我在一些文章中看到过这样的案例解决方案。要对所有情况使用单个查询,您可以为帖子列表创建一个特殊的终止节点。没有帖子的人会像:

(适用:人) - [:发布] - GT;(:PostListEnd)

现在,在所有情况下,您都可以运行查询:

MATCH (user:Person {id:#id})-[rel:POSTED]->(prev_post)
DELETE rel
CREATE (user)-[:POSTED]->(post:POST {post:"#post", created:timestamp()}),
       (post)-[:PREV]->(prev_post);

请注意,为prev_post指定了no标签,因此它可以匹配(:POST)或(:PostListEnd)。

运行查询后,有1个帖子的人就像:

(适用:人) - [:发布] - GT;(:POST) - [:PREV] - GT;(:PostListEnd)

由于PostListEnd节点没有自己的信息,因此您可以为所有用户提供相同的一个节点。

答案 2 :(得分:2)

在Neo4j v3.2开发人员手册中,它指定了如何创建由多个节点属性at this link组成的复合密钥:

CREATE CONSTRAINT ON (n:Person) ASSERT (n.firstname, n.surname) IS NODE KEY

但是,这仅适用于企业版,而不适用于社区。

答案 3 :(得分:0)

“CASE”与你要获得的if语句一样接近,我认为。

鉴于您的范围可能有限,FOREACH可能并不是那么糟糕。但我认为将查询分成两部分没有特别的缺点,特别是为了保持可读性,并且操作相当小。

只是我的两分钱。