【问题标题】:Creating multiple nodes using UNWIND in NEO4J when a node already exist当节点已存在时,在 NEO4J 中使用 UNWIND 创建多个节点
【发布时间】:2018-06-05 19:59:08
【问题描述】:

我正在使用 UNWIND 在 NEO4j 中创建多个节点。问题是如果其中一个节点是重复的,它将被拒绝并且整个查询失败。如果它们已经存在,我希望能够在相同节点之间创建多个关系......例如,一个朋友可能会收到来自同一个人的多个邀请。所以我有一组对象 [{email: xxx@mail.com},{email:yyy@mymail.com},...] 被邀请和赞助商的电子邮件赞助商电子邮件。电子邮件受到限制,因此创建副本的尝试将失败并拒绝整个查询。当没有重复时,以下工作正常。

MATCH (s {email: 'sponsor@gmail.com'})
UNWIND $arrayOfObjects as invitees
CREATE (i:Invitee) MERGE (s)-[r:INVITED {since: timestamp()}]->(i)
SET i=invitees

我尝试用 MERGE 替换 CREATE,认为 MERGE 会找到 MATCH 并继续创建关系,但它不起作用..我仍然收到重复错误。在执行查询之前没有清理 arrayOfObjects 是否有另一种方法可以做到这一点?我想要的是副本不会失败,而是与现有的 Invitee 节点建立关系。

【问题讨论】:

    标签: neo4j cypher


    【解决方案1】:

    您需要将 :Invitee 节点与受邀者电子邮件一起合并。就像现在一样,您正在创建空的 :Invitee 节点,并且仅在创建它们之后设置电子邮件地址。您需要将它们电子邮件地址合并。 (你也应该在你的第一个 MATCH 上使用一个标签,否则它会执行 AllNodesScan...我现在假设它是 :Invitee,但请用任何有意义的标签替换)。

    MATCH (s:Invitee {email: 'sponsor@gmail.com'})
    UNWIND $arrayOfObjects as invitee
    MERGE (i:Invitee {email:invitee.email}) 
    CREATE (s)-[r:INVITED {since: timestamp()}]->(i)
    

    【讨论】:

    • @InverseFalcon ...是的,我确实按照问题中的说明尝试了这个,但我得到了一个重复的错误,如上所述...我会仔细检查。另外,感谢标签提醒...我实际上使用了标签,但是您的提醒确实改善了问题+1
    • 最后一个MERGE 不太有意义,因为当前时间戳可能会匹配现有关系的时间戳。所以,结果是不确定的——你有时可能不会建立新的关系。如果用例总是想要一个新的关系,那么CREATE 会更有意义并且更有效。
    • 没错,我会把它改成 CREATE
    【解决方案2】:

    [编辑]

    您的MERGE 可以匹配任何现有的Invitee,并且您的SET 可以尝试将其email 值更改为非唯一值。这可能就是您违反约束的原因。

    如果您只想为每个被邀请者提供一个 INVITED 关系(带有最新时间戳),则此查询可能会满足您的要求:

    MATCH (s {email: 'sponsor@gmail.com'})
    UNWIND $arrayOfObjects as invitee
    MERGE (i:Invitee {email: invitee.email})
    ON CREATE SET i = invitee
    MERGE (s)-[r:INVITED]->(i)
    ON CREATE SET r.since = timestamp()
    

    此查询假定arrayOfObjects 中的每个映射都包含唯一的email 属性值。 (您还应该在:Invitee(email) 上创建indexuniqueness constraint 以加快第一个MERGE。)

    MERGE (s)-[r:INVITED {since: timestamp()}]->(i) 子句(指定当前时间戳)有缺陷,因为它不会检测到与旧的since 值的现有关系——因此它几乎总是会创建一个新关系。 MERGE (s)-[r:INVITED]->(i) 子句只会在不存在关系时创建关系。

    或者,如果您想跟踪每个邀请的时间戳,您可以将 since 值设为时间戳数组,如下所示:

    MATCH (s {email: 'sponsor@gmail.com'})
    UNWIND $arrayOfObjects as invitee
    MERGE (i:Invitee {email: invitee.email})
    ON CREATE SET i = invitee
    MERGE (s)-[r:INVITED]->(i)
    ON CREATE SET r.since = [timestamp()]
    ON MATCH SET r.since = r.since + timestamp()
    

    【讨论】:

    • 我确实在 UNWIND 之后使用了 MERGE,如问题中所述,但我仍然收到“带有电子邮件 xxxx 的节点 123 已存在”。是的,我希望它创建一个新关系来跟踪有多少邀请已发送给同一受邀者.....我会仔细检查我的代码
    • 您的MERGE 可以匹配any 现有的Invitee,并且您的SET 可以尝试将其email 值更改为不再是唯一的。另外,请参阅我的更新答案,了解有关如何跟踪每个邀请的建议。
    【解决方案3】:

    提交的两个答案都是很好的答案。我正在提交这个答案,并为后来出现的人提供一些细微差别。该问题的主要目标是能够为尚未接受的朋友创建多个邀请,并能够可视化这些邀请。以下是我决定的:

    WITH ['tom@abc.com', 'tony@mymail.com',michael@gmail.com'] AS coll
    UNWIND coll AS invitee
    WITH DISTINCT invitee
    MATCH (s:Sponsor {email: 'mary@gmail.com'})
    MERGE (i:Invitee {email: invitee})
    CREATE (s)-[r:INVITED {since: timestamp()}]->(i)
    RETURN r;   
    

    这使我可以为发送给同一个人的每个邀请创建多个关系,但前提是在不同的时间发送......我可以轻松查看。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-27
      • 1970-01-01
      相关资源
      最近更新 更多