如何在Neo4j中设置某种类型的所有关系 - 必要时替换旧关系?

时间:2015-08-03 20:55:28

标签: neo4j

我有一个事件的节点ID,以及托管该事件的用户的节点ID列表。我想更新这些(:USER) - [:HOSTS] - >(:EVENT)关系。我不想添加新的,我也想删除旧的。

注意:这是coffeescript语法,其中#{}是字符串插值,str()将为我转义任何字符。

现在我正在查询所有主持人:

MATCH (u:USER)-[:HOSTS]->(:EVENT {id:#{str(eventId)}})
RETURN u.id

然后我决定哪些主机是新主机,需要添加哪些主机,哪些主机是旧的,需要删除。对于旧的,我删除它们

  MATCH (:HOST {id:#{str(host.id)}})-[h:HOSTS]->(:EVENT {id:#{str(eventId)}})
  DELETE h

对于新的,我添加它们:

  MATCH (e:EVENT {id: #{str(eventId)}})
  MERGE (u:USER {id:#{str(id)}})
  SET u.name =#{str(name)}
  MERGE (u)-[:HOSTS]->(e)

所以我的问题是,我可以在一个查询中更有效地执行此操作吗?我想要设置新的关系,摆脱以前在新集合中不存在的关系。

1 个答案:

答案 0 :(得分:2)

如果我正确理解您的问题,您可以通过引入WITHFOREACH在单个查询中实现您的目标。在由

创建的示例图表上
CREATE (_1:User { name:"Peter" }),(_2:User { name:"Paul" }),(_3:User { name:"Mary" })
CREATE (_4:Event { name:"End of the world" })
CREATE _1-[:HOSTS]->_4, _2-[:HOSTS]->_4

您可以删除不再相关的主机,并添加新主机

WITH ["Peter", "Mary"] AS hosts, "End of the world" AS eventId
MATCH (event:Event { name:eventId })<-[r:HOSTS]-(u:User)
WHERE NOT u.name IN hosts
DELETE r
WITH COLLECT(u.name) AS oldHosts, hosts, event
WITH FILTER(h IN hosts 
            WHERE NOT h IN oldHosts) AS newHosts, event, oldHosts
FOREACH (n IN newHosts | 
    MERGE (nh:User { name:n })
    MERGE nh-[:HOSTS]->event
)

我做了一些假设,至少包括

  • 该活动的新主持人(:User)可能已经存在,因此MERGE (nh:User { name:n })而不是CREATE
  • [:HOSTS]应与事件断开连接,但不会从数据库中删除。
  • 您的咖啡脚本内容可以转换为参数,您可以将我的伪参数转换为参数。在我的示例查询中,我使用第一行模拟参数,但您可能需要根据实际将参数传递给查询的方式调整语法(我无法将咖啡变成Cypher)。

单击here以测试查询。将hosts数组的内容更改为["Peter", "Paul"],或更改为["Peter", "Dragon"]或任何对您有意义的值,然后重新运行查询以查看其工作原理。我已经使用name而非id来捕获节点,而且我已经模拟了参数,但您可以将查询转换为您想要的上下文执行它。

修改

重新评论,如果您希望查询也匹配不具有任何主机的事件,则需要使模式的-[:HOSTS]-部分成为可选项。通过将MATCH子句制动为两个来实现:

MATCH (event:Event { name:eventId })
OPTIONAL MATCH event<-[r:HOSTS]-(u:User)

查询的其余部分是相同的。