4

I want to add a value to an array if its not already there. So far my code looks something like this (note that both r.names and {name} are arrays, and [1] + [2] = [1,2]):

MERGE (r:resource {hash:{hash}})
ON CREATE SET r.names = {name}
ON MATCH SET r.names = r.names + {name}

but obviously if {name} is already in r.names, it just gets added again. How can I add {name} only if r.names doesn't already contain it?

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
J.J
  • 3,459
  • 1
  • 29
  • 35

2 Answers2

7

I guess you need to use the FOREACH + CASE WHEN trick: using a case when you use either a 1 element array (if your condition is true) or a 0 element array otherwise as iterator used in FOREACH. FOREACH cannot be used in a ON MATCH or ON CREATE handler, so we put it after the MERGE and use a coalesce to cover the case when r.names does not yet exist:

MERGE (r:Resource {hash:{hash}})
FOREACH(x in CASE WHEN {name} in r.names THEN [] ELSE [1] END | 
   SET r.names = coalesce(r.names,[]) + {name}
)
RETURN r.names
Stefan Armbruster
  • 39,465
  • 6
  • 87
  • 97
  • 1
    I wish i could give you more than 1 upvote and 1 like because this solution nailed it - thank you so much! Only thing I would note for others following along is that in the above example the parameter {name} is just a string, not an array. If its an array it will appear not to work since {name} will not be in r.names. But thats an easy fix. Now all i have to do is figure out how the hell this even works :P – J.J Jul 15 '15 at 16:29
  • Just to verify, based on Stefans explanation, shouldn't it be THEN [1] ELSE [] instead? – Koh Apr 11 '18 at 07:53
2

Use FILTER to get an array of the elements that aren't already in r.names and add them:

MERGE (r:resource {hash:{hash}})
ON CREATE SET r.names = {new_names}
ON MATCH SET r.names = r.names + FILTER(
    el FOR el in {new_names} IF NOT el IN r.names
)
Mark Amery
  • 143,130
  • 81
  • 406
  • 459