【问题标题】:Cypher query - Optional Create密码查询 - 可选创建
【发布时间】:2017-10-19 06:28:31
【问题描述】:

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

(user:Person)-[:POSTED]->(p1:POST)-[:PREV]->[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 循环两次(查询看起来有点复杂,我知道循环只会运行 1 次)? .

但是,这是我在研究this SO post 后能想到的唯一解决方案。我读到 in an older post 没有 if 语句这样的东西。

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

干杯

【问题讨论】:

    标签: neo4j cypher


    【解决方案1】:

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

    (:Person)-[:POSTED]->(: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 没有指定标签,因此它可以匹配 (:POST) 或 (:PostListEnd)。

    运行查询后,有 1 个帖子的人会是这样的:

    (:Person)-[:POSTED]->(:POST)-[:PREV]->(:PostListEnd)

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

    【讨论】:

      【解决方案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)
      )
      

      【讨论】:

        【解决方案3】:

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

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

        但是,这仅适用于企业版,不适用于社区。​​p>

        【讨论】:

          【解决方案4】:

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

          鉴于您的范围可能有限,因此 FOREACH 可能还不错。但我认为将查询分成两部分并没有什么特别的缺点,尤其是为了保持它的可读性并且考虑到操作相当小。

          只要我的两分钱。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-11-29
            • 1970-01-01
            • 2016-12-22
            • 2013-09-29
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多