Некоторые странные результаты apoc.coll.zip()

#arrays #cypher #nested-lists #neo4j-apoc #unwind

Вопрос:

Я создаю 3 тестовых узла со свойствами имен «a», «b», «c» и использую apoc.coll.zip() их для объединения двух списков вместе:

 MATCH (n:test) 
WITH collect(n.name) as nodes 
WITH apoc.coll.zip(nodes, range(0, size(nodes))) as pairs 
RETURN pairs;

 -------------------------------- 
| pairs                          |
 -------------------------------- 
| [["a", 0], ["b", 1], ["c", 2]] |
 -------------------------------- 
 

Результат ожидаемый. Что интересно, так это когда я изменяю запрос либо путем добавления другого столбца в RETURN предложение, либо путем UNWIND добавления пары.

1. RETURN pairs,n.name;

 MATCH (n:test)
WITH n, collect(n.name) as nodes
WITH n, apoc.coll.zip(nodes, range(0, size(nodes))) as pairs 
RETURN pairs,n.name;
 --------------------- 
| pairs      | n.name |
 --------------------- 
| [["a", 0]] | "a"    |
| [["b", 0]] | "b"    |
| [["c", 0]] | "c"    |
 --------------------- 
 

Я ожидаю, что результат будет точно таким же с запросом:

 MATCH (n:test) 
WITH n, [["a", 0], ["b", 1], ["c", 2]] as nested 
RETURN nested, n.name;

 ---------------------––––––––––––––––––-- 
| pairs                          | n.name |
 ---------------------––––––––––––––––––-- 
| [["a", 0], ["b", 1], ["c", 2]] | "a"    |
| [["a", 0], ["b", 1], ["c", 2]] | "b"    |
| [["a", 0], ["b", 1], ["c", 2]] | "c"    |
 ---------------------––––––––––––––––––-- 
 

2. UNWIND pairs as pair RETURN pairs

 MATCH (n:test)
WITH n, collect(n.name) as nodes
WITH n, apoc.coll.zip(nodes, range(0, size(nodes))) as pairs
UNWIND pairs as pair
RETURN pairs;

 ------------ 
| pairs      |
 ------------ 
| [["a", 0]] |
| [["b", 0]] |
| [["c", 0]] |
 ------------ 
 

Я ожидаю, что результат будет ничем не отличаться от отсутствия UNWIND предложения:

  -------------------------------- 
| pairs                          |
 -------------------------------- 
| [["a", 0], ["b", 1], ["c", 2]] |
 -------------------------------- 
 

3. UNWIND pairs as pair RETURN pair

 MATCH (n:test)
WITH n, collect(n.name) as nodes
WITH n, apoc.coll.zip(nodes, range(0, size(nodes))) as pairs
UNWIND pairs as pair
RETURN pair;
 ---------- 
| pair     |
 ---------- 
| ["a", 0] |
| ["b", 0] |
| ["c", 0] |
 ---------- 
 

Я ожидаю, что результат будет ничем не отличаться от простого UNWIND вложенного списка:

 UNWIND [["a", 0], ["b", 1], ["c", 2]] as list 
RETURN list;

 ---------- 
| list     |
 ---------- 
| ["a", 0] |
| ["b", 1] |
| ["c", 2] |
 ---------- 
 

Вы знаете, почему это происходит? Они, похоже, не объясняются в RETURN документации и UNWIND документации.

Ответ №1:

Для всех 3 перечисленных запросов ключевым моментом является,

 ...
WITH n, collect(n.name) as nodes
...
 

collect является агрегирующей функцией, и ее можно сгруппировать. Указание «n» в WITH предложении приводит к тому, что он выполняет «группировку по», аналогичную группировке SQL. Поэтому, если у вас есть 3 узла, вы получите 3 результата.

Вы можете выполнить отладку RETURN , выполнив ее после WITH , чтобы увидеть результат на каждом шаге, например так,

 MATCH (n:test)
WITH n, collect(n.name) as nodes
RETURN n, nodes
 

Комментарии:

1. хмм. Итак, способ исправить это-создать специальное WITH предложение для n ? Как только появится WITH предложение для переменной, будет ли оно выдвинуто, даже если в других WITH предложениях его нет?

2. один из упрощенных способов взглянуть на это-представить каждое предложение «WITH» как точку остановки в выполнении, где собираются промежуточные результаты, а затем отправляются в качестве входных данных в следующую часть инструкции cypher

3. да, но когда в следующей части будет другое WITH предложение, и мы больше не будем напоминать переменную, тогда она снова будет забыта?

4. да, это так

5. но если это так, то как может сработать исправление? n будет забыто сразу после WITH collect(n.name) as nodes