Cypher:将关系属性添加为不同的值

时间:2018-05-14 18:15:02

标签: neo4j cypher

我尝试做的是写一个查询 - 我已经把它作为一个web服务(在本地机器上工作,所以我得到了名字和人作为参数) - 它连接了拥有相同爱好的人和将爱好设置为关系属性作为数组。 我的第一次尝试是;

MERGE (aa:Person{name:$name})
WITH aa, $people as people
FOREACH (person IN people |
MERGE (bb:Person{name:person.name})
MERGE (bb)-[r:SHARESSAMEHOBBY]->(aa)
ON MATCH SET r.hobbies = r.hobbies + person.hobby
ON CREATE SET r.hobbies = [person.hobby])

然而,这导致重复的属性元素,如["游泳","游泳"]

我试图只设置唯一的属性。然后我尝试了以下查询;

MERGE (aa:Person{name:$name})
WITH aa, $people as people FOREACH (person IN people | MERGE (bb:Person{name:person.name}) MERGE (bb)-[r:SHARESSAMEHOBBY]->(aa)
WITH r, COALESCE(r.hobbies, []) + person.hobby AS hobbies
UNWIND hobbies as unwindedHobbies
WITH r, collect(distinct, unwindedHobbies) AS unique
set r.as = unique)

但是现在它给了我语法错误;

 errorMessage = "[Neo.ClientError.Statement.SyntaxError] Invalid use of WITH inside FOREACH

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

这应该有效:

MERGE (aa:Person {name: $name})
WITH aa
UNWIND $people AS person
MERGE (bb:Person {name: person.name})
MERGE (bb)-[r:SHARESSAMEHOBBY]-(aa)
WITH r, person, CASE
  WHEN NOT EXISTS(r.hobbies) THEN {new: true}
  WHEN NOT (person.hobby IN r.hobbies) THEN {add: true}
  END AS todo
FOREACH(ignored IN todo.new | SET r.hobbies = [person.hobby])
FOREACH(ignored IN todo.add | SET r.hobbies = r.hobbies + person.hobby);

您实际上有2个问题,上述查询同时解决了这两个问题:

  1. 如果SHARESSAMEHOBBY关系已存在于相反的方向(从aabb),则以下MERGE子句会导致不必要的创建第二个SHARESSAMEHOBBY关系(从bbaa):

    MERGE(bb) - [r:SHARESSAMEHOBBY] - >(aa)

    为了避免这种情况,您应该使用非方向关系模式(MERGE允许,但不允许CREATE)来匹配任一方向的关系,如下所示:

    MERGE(bb) - [r:SHARESSAMEHOBBY] - (aa)

  2. 您需要确定是否有必要初始化新的hobbies列表或将person.hobby值添加到尚未具有该值的现有r.hobbies列表中。上面的查询使用CASE子句分配给todo NULL或带有键的地图,指示要执行的其他工作。然后,它会使用FOREACH子句来执行每个要执行的操作。