UNWIND

Introduction

The UNWIND clause in Cypher transforms a list into a sequence of individual rows. Each element in the input list becomes a separate row, with the specified variable bound to that element. If the expression evaluates to NULL, UNWIND produces a single row with the variable set to NULL. If the expression evaluates to an empty list, UNWIND produces no rows. This behavior is consistent across AGE.

UNWIND is especially useful when processing list-valued properties on vertices or edges, or when iterating over a collection of values within a query.

Examples

Data Preparation

The following examples use this reference dataset:

SELECT * FROM cypher('cypher_unwind', $$
    CREATE (n {name: 'node1', a: [1, 2, 3]}),
           (m {name: 'node2', a: [4, 5, 6]}),
           (o {name: 'node3', a: [7, 8, 9]}),
           (n)-[:KNOWS]->(m),
           (m)-[:KNOWS]->(o)
$$) AS (i agtype);

Basic UNWIND: Integer Literal List

This example demonstrates the simplest use of UNWIND: expanding a literal list of integers into individual rows.

SQL Query

SELECT * FROM cypher('cypher_unwind', $$
    UNWIND [1, 2, 3] AS i
    RETURN i
$$) AS (i agtype);

Output

i
---
1
2
3
(3 rows)

UNWIND with Node Properties

This example shows how to use UNWIND to process a list-valued property on nodes, using the reference data.

SQL Query

SELECT * FROM cypher('cypher_unwind', $$
    MATCH (n)
    WITH n.a AS a
    UNWIND a AS i
    RETURN *
$$) AS (i agtype, j agtype);

Output

i | j
-----------+---
[1, 2, 3] | 1
[1, 2, 3] | 2
[1, 2, 3] | 3
[4, 5, 6] | 4
[4, 5, 6] | 5
[4, 5, 6] | 6
[7, 8, 9] | 7
[7, 8, 9] | 8
[7, 8, 9] | 9
(9 rows)

Nested UNWIND

UNWIND can be nested to flatten deeply nested lists.

SQL Query

SELECT * FROM cypher('cypher_unwind', $$
    WITH [[1, 2], [3, 4], 5] AS nested
    UNWIND nested AS x
    UNWIND x AS y
    RETURN y
$$) AS (i agtype);

Output

i
---
1
2
3
4
5
(5 rows)

UNWIND with Path Function: nodes()

UNWIND can be used with path functions such as nodes() to process individual vertices in a path.

SQL Query

SELECT * FROM cypher('cypher_unwind', $$
    MATCH p=(n)-[:KNOWS]->(m)
    UNWIND nodes(p) AS node
    RETURN node
$$) AS (i agtype);

Output

i
-----------------------------------------------------------------------------------------------
{"id": 281474976710657, "label": "", "properties": {"a": [1, 2, 3], "name": "node1"}}::vertex
{"id": 281474976710658, "label": "", "properties": {"a": [4, 5, 6], "name": "node2"}}::vertex
{"id": 281474976710658, "label": "", "properties": {"a": [4, 5, 6], "name": "node2"}}::vertex
{"id": 281474976710659, "label": "", "properties": {"a": [7, 8, 9], "name": "node3"}}::vertex
(4 rows)

UNWIND with Path Function: relationships()

Similarly, UNWIND can be used with relationships() to process individual relationships in a path.

SQL Query

SELECT * FROM cypher('cypher_unwind', $$
    MATCH p=(n)-[:KNOWS]->(m)
    UNWIND relationships(p) AS relation
    RETURN relation
$$) AS (i agtype);

Output

i
---------------------------------------------------------------------------------------------------------------------------
{"id": 844424930131969, "label": "KNOWS", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge
{"id": 844424930131970, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710658, "properties": {}}::edge
(2 rows)

UNWIND with Path Function: relationships() and Explicit Path Unwinding

This example demonstrates unwinding relationships from a path that is itself explicitly wrapped in a list.

SQL Query

SELECT * FROM cypher('cypher_unwind', $$
    MATCH p=({name:'node1'})-[e:KNOWS*]->({name:'node3'})
    UNWIND [p] AS path
    UNWIND relationships(path) AS edge
    RETURN edge
$$) AS (i agtype);

Output

i
---------------------------------------------------------------------------------------------------------------------------
 {"id": 844424930131969, "label": "KNOWS", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge
 {"id": 844424930131970, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710658, "properties": {}}::edge
(2 rows)

UNWIND with SET Clause

UNWIND can be combined with SET to update properties based on the unwound values.

SQL Query

SELECT * FROM cypher('cypher_unwind', $$
    MATCH p=(n)-[:KNOWS]->(m)
    UNWIND nodes(p) AS node
    SET node.type = 'vertex'
$$) AS (i agtype);

Output

i
---
(0 rows)

UNWIND with NULL

This example illustrates how UNWIND handles NULL. Understanding this behavior is critical when working with optional list properties or expressions that may evaluate to NULL.

SQL Query

SELECT * FROM cypher('cypher_unwind', $$
    UNWIND NULL AS i
    RETURN i
$$) AS (i agtype);

Output

i
---

(1 row)