原文链接: https://gist.github.com/jruts/fe782ff2531d509784a24b655ad8ae76
这个问题很好理解,在数据库中有id相同的结点存在。
这事看上去挺简单,但当真真做时才知道,并没有想的那么容易。
第一步
我首先尝试着找出重复的结点,这个看上去很简单。
MATCH (g:geo)
WITH g.id as id, collect(g) AS nodes
WHERE size(nodes) > 1
RETURN nodes
这个查询得到所有geo标签的结点,然后创建id属性个数大于1的结点列表。
这个查询结果就是得到重复的带有geo标签的结点列表。示例结果如下:
nodesgeo:123, geo:123geo: 578, geo: 578, geo:578
第二步
接下来我要尝试着删除重复的,当然要留一个。
MATCH (g:geo)
WITH g.id as id, collect(g) AS nodes
WHERE size(nodes) > 1
FOREACH (g in tail(nodes) | DELETE g)
这个语句会出错:
org.neo4j.kernel.api.exceptions.ConstraintViolationTransactionFailureException: Cannot delete node<866>, because it still has relationships. To delete this node, you must first delete its relationships.
看上去我们好像快要搞定了,但是我先解释一下这个查询。
我们使用之前相应的查询,但是我们没有返回结点,而是遍历 tail(nodes) 的结点,依次删除这些结点。
tail 函数能够返回一个列表中除了首结点之外的所有结点,所以,我们能确保有一个结点不被删除。
第三步
上面的错误显示,我们在删除结点之前需要先删除他们关系。
MATCH (g:geo)
WITH g.id as id, collect(g) AS nodes
WHERE size(nodes) > 1
UNWIND tail(nodes) as tails
MATCH (tails)-[r]-()
DELETE r
重复的结点的关系被成功删除了,当我们再次运行第二步的语句时,重复的结点也被删除了。
解决方案
先删除重复结点的重复关系
MATCH (g:geo)
WITH g.id as id, collect(g) AS nodes
WHERE size(nodes) > 1
UNWIND tail(nodes) as tails
MATCH (tails)-[r]-()
DELETE r
再删除重复的结点
MATCH (g:geo)
WITH g.id as id, collect(g) AS nodes
WHERE size(nodes) > 1
FOREACH (g in tail(nodes) | DELETE g)
希望这些能帮助到大家。
译者言:事实上有更简单的方法,一步完成这种删除。
MATCH (g:geo)
WITH g.id as id, collect(g) AS nodes
WHERE size(nodes) > 1
FOREACH (g in tail(nodes) | DETACH DELETE g)