UNWIND

The UNWIND clause makes it possible to transform any list back into individual rows. These lists can be parameters that were passed in, previously collect-ed result, or other list expressions.

Neo4j does not guarantee the row order produced by UNWIND. The only clause that guarantees a specific row order is ORDER BY.

Common usage of the UNWIND clause:

  • Create distinct lists.

  • Create data from parameter lists that are provided to the query.

The UNWIND clause requires you to specify a new name for the inner values.

Unwinding a list

We want to transform the literal list into rows named x and return them.

Query
UNWIND [1, 2, 3, null] AS x
RETURN x, 'val' AS y

Each value of the original list — including null — is returned as an individual row.

Table 1. Result
x y

1

"val"

2

"val"

3

"val"

<null>

"val"

Rows: 4

Creating a distinct list

We want to transform a list of duplicates into a set using DISTINCT.

Query
WITH [1, 1, 2, 2] AS coll
UNWIND coll AS x
WITH DISTINCT x
RETURN collect(x) AS setOfVals

Each value of the original list is unwound and passed through DISTINCT to create a unique set.

Table 2. Result
setOfVals

[1,2]

Rows: 1

Using UNWIND with any expression returning a list

Any expression that returns a list may be used with UNWIND.

Query
WITH
  [1, 2] AS a,
  [3, 4] AS b
UNWIND (a + b) AS x
RETURN x

The two lists — a and b — are concatenated to form a new list, which is then operated upon by UNWIND.

Table 3. Result
x

1

2

3

4

Rows: 4

Using UNWIND with a list of lists

Multiple UNWIND clauses can be chained to unwind nested list elements.

Query
WITH [[1, 2], [3, 4], 5] AS nested
UNWIND nested AS x
UNWIND x AS y
RETURN y

The first UNWIND results in three rows for x, each of which contains an element of the original list (two of which are also lists); namely, [1, 2], [3, 4], and 5. The second UNWIND then operates on each of these rows in turn, resulting in five rows for y.

Table 4. Result
y

1

2

3

4

5

Rows: 5

Using UNWIND with an empty list

Using an empty list with UNWIND will produce no rows, irrespective of whether or not any rows existed beforehand, or whether or not other values are being projected.

Essentially, UNWIND [] reduces the number of rows to zero, and thus causes the query to cease its execution, returning no results. This has value in cases such as UNWIND v, where v is a variable from an earlier clause that may or may not be an empty list — when it is an empty list, this will behave just as a MATCH that has no results.

Query
UNWIND [] AS empty
RETURN 'literal_that_is_not_returned'
Table 5. Result

(empty result)

Rows: 0

To avoid inadvertently using UNWIND on an empty list, CASE may be used to replace an empty list with a null:

WITH [] AS list
UNWIND
  CASE
    WHEN list = [] THEN [null]
    ELSE list
  END AS emptylist
RETURN emptylist

Using UNWIND with an expression that is not a list

Using UNWIND on an expression that does not return a list, will return the same result as using UNWIND on a list that just contains that expression. As an example, UNWIND 5 is effectively equivalent to UNWIND[5]. The exception to this is when the expression returns null — this will reduce the number of rows to zero, causing it to cease its execution and return no results.

Query
UNWIND null AS x
RETURN x, 'some_literal'
Table 6. Result

(empty result)

Rows: 0

Creating nodes from a list parameter

Create a number of nodes and relationships from a parameter-list without using FOREACH.

Parameters
{
  "events" : [ {
    "year" : 2014,
    "id" : 1
  }, {
    "year" : 2014,
    "id" : 2
  } ]
}
Query
UNWIND $events AS event
MERGE (y:Year {year: event.year})
MERGE (y)<-[:IN]-(e:Event {id: event.id})
RETURN e.id AS x ORDER BY x

Each value of the original list is unwound and passed through MERGE to find or create the nodes and relationships.

Table 7. Result
x

1

2

Rows: 2
Nodes created: 3
Relationships created: 2
Properties set: 3
Labels added: 3