David
David

Reputation: 247

Merge existing records in neo4j, remove duplicates, keep optional relationships

This is similar to Merge existing records in neo4j, remove duplicates, keep relationships, except that the nodes I want to merge have 0-2 relationships I want to keep.

Take the graph generated by:

create (:Person {name:"Bob"})-[:RELATED_TO]->(:Person {name:"Jane"})-[:FRIENDS_WITH]->(:Person {name:"Tim"})<-[:FRIENDS_WITH]-(:Person {name:"Jane"}),
(:Person {name:"Sally"})-[:RELATED_TO]->(:Person {name:"Jane"})

I want to merge the duplicate Jane nodes, preserving the RELATED_TO and FRIENDS_WITH relationships, removing the duplicates.

From the other question I can get as far as:

match (p:Person {name:"Jane"})
with p.name as name, collect(p) as ps, count(*) as pcount
where pcount > 1
with head(ps) as first, tail(ps) as rest
unwind rest as to_delete
return to_delete

But I can't seem to get the matches and/or optional matches correct for merging. I tried chaining optional matches and doing the merge in one statement and neo4j gives me a Statement.ExecutionFailure with no additional message. I tried breaking out the merges into each match and ended up with "other node is null". Thoughts?

Upvotes: 1

Views: 834

Answers (1)

Christophe Willemsen
Christophe Willemsen

Reputation: 20175

The following query is working. On a side note, for this kind of refactoring I would love the day when it would be possible to set a relationship type with a dynamic variable :

MATCH (n:Person { name:"Jane" })
WITH collect(n) AS janes
WITH head(janes) AS superJane, tail(janes) AS badJanes 
UNWIND badJanes AS badGirl
OPTIONAL MATCH (badGirl)-[r:FRIENDS_WITH]->(other)
OPTIONAL MATCH (badGirl)<-[r2:RELATED_TO]-(other2)
DELETE r, r2, badGirl
WITH superJane, collect(other) AS friends, collect(other2) AS related
FOREACH (x IN friends | MERGE (superJane)-[:FRIENDS_WITH]->(x))
FOREACH (x IN related | MERGE (x)-[:RELATED_TO]->(superJane))

Result :

enter image description here

Upvotes: 4

Related Questions