1
votes

I am writing the below Neo4j Cypher query to add new Partand remove old Part from Vehicle node. I am using Neo4j (version 3.4.1)

newParts and removedParts are my parameters. They are lists of String.

with {newParts} AS newParts
unwind newParts as newPart
match (r:Vehicle) where id(r)=639
merge (r)-[:HAS_PART]->(np:Part{name:newPart})
on create np+={lastModifiedDateTime:localdatetime(), createdDateTime:localdatetime()}
with r optional match (r)-[rel:HAS_PART]-(p:Part) where p.name in {removedParts}
delete rel
with r match q=(r)--()
return nodes(q), relationships(q))

It works fine when I provide newParts parameter as non-empty.

However when this is empty, I don't get back my final nodes and relationships. I do understand why that is happening because unwind stops execution when the list is empty. I tried moving with..unwind part below del and it successfully deletes removedParts Part. However it doesn't return final nodes and relationship as they come after unwind.

I am not sure how to make this work with empty newParts parameter as well. I was trying to use case but I think case doesn't work with nodes and relationships.

Any help or pointers would be highly appreciated.

Thanks in advance

V

2
Have you tried using case size(newParts) ...?rickhg12hs

2 Answers

2
votes

Idea

You could use the conditional cypher execution of the APOC user library in combination with a non-empty check of your parameter newParts. Please prefer apoc.do.when over apoc.when as it is executed in a read/write context, which is necessary for the MERGE clause.

Proposed solution

WITH $newParts AS newParts, $removedParts AS removedParts
CALL apoc.do.when(
size($newParts) > 0,
// true case
'
  UNWIND newParts AS newPart
  MATCH (r:Vehicle) WHERE id(r)=639
  MERGE (r)-[:HAS_PART]->(np:Part{name:newPart})
  ON CREATE np+={lastModifiedDateTime:localdatetime(), createdDateTime:localdatetime()}
  RETURN r;
',
// false case
'
  UNWIND newParts AS newPart
  MATCH (r:Vehicle) WHERE id(r)=639
  RETURN r;
',
{newParts: newParts}) YIELD value AS result
WITH DISTINCT result.r AS r, removedParts
OPTIONAL MATCH (r)-[rel:HAS_PART]-(p:Part) WHERE p.name IN removedParts
DELETE rel
WITH DISTINCT r 
MATCH q=(r)--()
RETURN nodes(q), relationships(q);

Explanation

  • line 2: calling the if-then-else construct of the APOC user library
  • line 3: the to be evaluated condition, in this case the check if the parameter newParts is not empty
  • line 5-11: the if section, which hands over the Vehicle r
  • line 13-17: the else section
  • line 18: defining the parameter that have to be provided to the if-then-else construct and retrieving the result from it
1
votes

I was able to come up with an answer for my own question thanks to the advice and suggestion from Neo4j admins on Neo4j slack channel.

If you want to use plain Cypher query you can use the below answer:

MATCH (r:Vehicle) WHERE id(r)=639
FOREACH(newPart IN {newParts}| 
MERGE (np:Part{id:newPart})
ON CREATE SET np+={partProperties}
MERGE (r)-[:HAS_PART]->(np))
WITH DISTINCT r SET r+={vehicleProperties} 
WITH DISTINCT r OPTIONAL MATCH p=(r)-[rel:HAS_PART]-(p:Part) where p.name in {removedParts} 
DELETE rel 
WITH DISTINCT r 
MATCH q=(r)--() 
RETURN q

Hope somebody finds it helpful!

Regards, V