vital
vital

Reputation: 1348

Add node to linked list after given node in cypher

I have the following graph:

(Boxer)-[:STARTS]->(Round)-[:CONTINUES]->(Round)-[:CONTINUES]->(Round)-[:CONTINUES]->(Round)

I want to insert a new Round AFTER a specified Round called prevRound. Right now I am doing this:

MERGE (round:Round {uuid: $round.uuid})
MERGE (prevRound:Round {uuid: $prevRound.uuid})
MERGE (prevRound)-[oldRel:CONTINUES]->(nextRound)
MERGE (prevRound)-[:CONTINUES]->(round)-[:CONTINUES]->(nextRound)
DELETE oldRel

This works but it will actually create an empty node when I try to insert a node at the end of the list. I know it's because of:

MERGE (prevRound)-[oldRel:CONTINUES]->(nextRound)

Indeed, this will create a nextRound node when it does not exists.

How can I prevent that? I tried with optional match but it did not work at well.

Upvotes: 0

Views: 42

Answers (1)

InverseFalcon
InverseFalcon

Reputation: 30397

MERGE is not the right clause to use here, since as you saw it will create the pattern if it does not exist, giving you a blank node and a relationship to it from prevRound. OPTIONAL MATCH is the correct clause to use for that line (though you do need a WITH clause between it and the preceding MERGE)...but a better approach would actually be to rearrange your query a little (see the last paragraph).

You should also split up the last MERGE, since a longer pattern like this will likely not do what you expect it to do under certain circumstances. Read our knowledge base article on understanding how MERGE works for some of the finer details that might otherwise trip you up.

We can actually accomplish what you want fairly simply by rearranging parts of your query.

MERGE (round:Round {uuid: $round.uuid})
MERGE (prevRound:Round {uuid: $prevRound.uuid})
WITH round, prevRound
OPTIONAL MATCH (prevRound)-[oldRel:CONTINUES]->(nextRound)
DELETE oldRel
MERGE (prevRound)-[:CONTINUES]->(round)
WITH round, nextRound, oldRel
WHERE nextRound IS NOT NULL
MERGE (round)-[:CONTINUES]->(nextRound)

We guard the MERGE between round and nextRound by the preceding WHERE clause, which filters out any rows where nextRound doesn't exist.

A perhaps simpler way to do this, though slightly less efficient, is to deal with the nodes you know exist first, round and prevRound, then deal with the pattern that may or may not exist, the MATCH to the old node, though you will need to do a bit of filtering, since the MATCH will also pick of the relationship you just created to round:

MERGE (round:Round {uuid: $round.uuid})
MERGE (prevRound:Round {uuid: $prevRound.uuid})
MERGE (prevRound)-[:CONTINUES]->(round)
WITH round, prevRound
MATCH (prevRound)-[oldRel:CONTINUES]->(nextRound)
WHERE nextRound <> round
DELETE oldRel
MERGE (round)-[:CONTINUES]->(nextRound)

You might also consider if there are any places where you know such a relationship does not exist, and if so, use CREATE instead of MERGE. I have a feeling the last MERGE here probably could be a CREATE instead.

Upvotes: 1

Related Questions