我正在尝试创建一个类似社交网络的结构。 我想创建一个看起来像这样的帖子的时间表
(用户:人) - [:发布] - 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语句这样的东西。
编辑:问题是:将两个案例都包含在一个查询中甚至是好的,因为我知道“无案例”只会发生一次而所有其他案例都是“至少一个帖子”吗?
干杯
答案 0 :(得分:2)
我也没有看到比使用FOREACH
更好的解决方案。
但是,我认为我可以使您的查询更有效率。我的解决方案基本上将2 FOREACH
个测试合并为1,因为prev_post
和rel
必须同时是NULL
或非NULL
。它还结合了CREATE
和MERGE
(无论如何都应该是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
但是,这仅适用于企业版,而不适用于社区。 p>
答案 3 :(得分:0)
“CASE”与你要获得的if语句一样接近,我认为。
鉴于您的范围可能有限,FOREACH可能并不是那么糟糕。但我认为将查询分成两部分没有特别的缺点,特别是为了保持可读性,并且操作相当小。
只是我的两分钱。