UNWIND

Введение

Предложение UNWIND в Cypher преобразует список в последовательность отдельных строк. Каждый элемент входного списка становится отдельной строкой, а указанная переменная связывается с этим элементом. Если выражение вычисляется в NULL, UNWIND создаёт одну строку, в которой переменная равна NULL. Если выражение вычисляется в пустой список, UNWIND не создаёт ни одной строки. Такое поведение одинаково во всех реализациях AGE.

UNWIND особенно полезен при обработке свойств вершин или рёбер, содержащих списки, а также при итерации по коллекции значений внутри запроса.

Примеры

Подготовка данных

Все приведённые ниже примеры используют следующий набор тестовых данных:

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);

Базовый UNWIND: Список целочисленных литералов

Этот пример демонстрирует простейшее применение UNWIND: расширение литерального списка целых чисел в отдельные строки.

SQL-запрос

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

Результат

i
---
1
2
3
(3 строки)

UNWIND со свойствами вершин

В этом примере показано, как использовать UNWIND для обработки свойства вершины, содержащего список, на основе подготовленных данных.

SQL-запрос

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

Результат

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 строк)

Вложенный UNWIND

UNWIND может быть вложен для «расплющивания» глубоко вложенных списков.

SQL-запрос

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);

Результат

i
---
1
2
3
4
5
(5 строк)

UNWIND с функцией пути: nodes()

UNWIND можно использовать совместно с функциями путей, например nodes(), чтобы обрабатывать отдельные вершины в пути.

SQL-запрос

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

Результат

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 строки)

UNWIND с функцией пути: relationships()

Аналогично, UNWIND можно использовать с relationships() для обработки отдельных рёбер в пути.

SQL-запрос

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

Результат

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 строки)

UNWIND с функцией пути: relationships() и явным разворачиванием пути

В этом примере демонстрируется разворачивание рёбер из пути, который сам по себе явно помещён в список.

SQL-запрос

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);

Результат

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 строки)

UNWIND с предложением SET

UNWIND можно комбинировать с SET, чтобы обновлять свойства на основе развернутых значений.

SQL-запрос

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

Результат

i
---
(0 строк)

UNWIND с NULL

Этот пример иллюстрирует, как UNWIND обрабатывает NULL. Понимание этого поведения критически важно при работе с необязательными свойствами-списками или выражениями, которые могут выдавать NULL.

SQL-запрос

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

Результат

i
---

(1 строка)