Avoid unwinding empty list while also avoiding creation of nodes with null properties

Take this example query, which is a fragment of a larger query.

WITH ['foo', 'bar', 'baz'] AS theList, 42 AS someVal
UNWIND (CASE theList WHEN [] THEN [null] ELSE theList END) AS l
CREATE (w:Word {content: l})

Here, ['foo', 'bar', 'baz'] will be input from the user in the application. It will be a list, but it could also be an empty list.

If it's an empty list, I want to have zero nodes created, and 42 should still be returned.
If it's not an empty list, a Word node should be created for each element of the list, and 42 should be returned.

At the moment, it creates a word with no properties, due to using the CASE pattern to avoid unwinding an empty list (which would skip the RETURN clause). Is this possible? By the way, FOREACH is not an option in this particular case.

Your cypher does not work because unwinding [null] still results in one row. You can use this:

WITH ['foo', 'bar', 'baz'] AS theList, 42 AS someVal
call apoc.do.when(size(theList) > 0, "UNWIND theList as l CREATE (w:Word {content: l}) return l", "",{theList:theList}) YIELD value
with someVal
RETURN distinct someVal
1 Like

For these cases, when you only want to use updating clauses (CREATE, MERGE, SET, REMOVE, DELETE) you can use a FOREACH instead of an UNWIND, and that lets you dodge the problem entirely:

WITH ['foo', 'bar', 'baz'] AS theList, 42 AS someVal
FOREACH (item IN theList | 
  CREATE (:Word {content: item}))
RETURN someVal AS sv2;

Cardinality will not increase, so you stay at a single row throughout the entire query, so no need to use DISTINCT later on.

FOREACH on an empty list is essentially a no-op for the contained Cypher, no filtering of rows will occur.

1 Like