NullPointer с использованием apoc.map.fromPairs в Neo4j Cypher Query

Я использую приведенный ниже код, чтобы вернуть все узлы с тремя обращенными внутрь ребрами из определенного узла (id (65)) и отформатировать результат как график JSON с помощью процедуры apoc.map.fromPairs. Я получаю сообщение об ошибке, если нет узлов, удаленных на 3 ребра от начального узла.

Похоже, что процедура apoc.map.fromPairs выдает следующую ошибку, выполняющуюся против "null", используемого для отсутствующих частей шаблона, когда я включаю оператор OPTIONAL.

Не удалось вызвать функцию apoc.map.fromPairs: вызвано: java.lang.NullPointerException

Любые предложения, как я могу это преодолеть. Я попытался написать оператор CASE, чтобы проверить, есть ли на карте какие-либо ключи, но также не смог заставить его работать.

*******************************************************************************************
// ** 
// ** Author: MOS
// ** Date: 02/03/2017
// ** Description: Returns all nodes and relationships that are within 3 inward
// ** hops of the requested node. The response is formatted as Graph JSON.
// ** 
// *******************************************************************************************
OPTIONAL MATCH (l0) <-[r1]- (l1) <-[r2]- (l2) <-[r3]- (l3)
WHERE ID(l0) = 65
WITH [
       {
            id: id(l0),
            label: labels(l0),
            type:"",
            metadata: apoc.map.fromPairs([key IN keys(l0) | [key, l0[key]]])  
        },
        {
            id: id(l1),
            label: labels(l1),
            type:"",
            metadata: apoc.map.fromPairs([key IN keys(l1) | [key, l1[key]]])
        },
        {
            id: id(l2),
            label: labels(l2),
            type:"",
            metadata: apoc.map.fromPairs([key IN keys(l2) | [key, l2[key]]])
        },
        {
            id: id(l3),
            label: labels(l3),
            type:"",
            metadata: apoc.map.fromPairs([key IN keys(l3) | [key, l3[key]]])
        }
] as nodes,
[
        { 
            id: id(r1),
            source: ID(startNode(r1)),
            relation: type(r1),
            target: ID(endNode(r1)), 
            directed: "true",
            metadata: apoc.map.fromPairs([key IN keys(r1) | [key, r1[key]]])
        },
        { 
            id: id(r2),
            source: ID(startNode(r2)),
            relation: type(r2),
            target: ID(endNode(r2)), 
            directed: "true",
            metadata: apoc.map.fromPairs([key IN keys(r2) | [key, r2[key]]])
        },
        { 
            id: id(r3),
            source: ID(startNode(r3)),
            relation: type(r3),
            target: ID(endNode(r3)), 
            directed: "true",
            metadata: apoc.map.fromPairs([key IN keys(r3) | [key, r3[key]]])
        }
] as edges
UNWIND nodes as node
UNWIND edges as edge
RETURN
{
 graph: 
    {
      type:"",
      label: "",    
      directed: "true",
      node: collect(distinct node) ,
      edges: collect(distinct edge),
      metadata:{
                  countNodes: count(distinct node),
                  countEdges: count(distinct edge)
               }
  }
}

Спасибо большое


person n4nite    schedule 02.03.2017    source источник
comment
Разве вы не можете просто использовать properties(r1)?   -  person Michael Hunger    schedule 02.03.2017


Ответы (2)


Вы можете немного упростить свой запрос, а также обобщить его:

OPTIONAL MATCH path = (x)<-[*..3]-() WHERE ID(x) = 65

UNWIND nodes(path) as node
UNWIND rels(path) as rel

WITH collect(distinct node) as nodes,collect(distinct rel) as rels
// WITH apoc.coll.flatten(collect(nodes(path))) as nodes, apoc.coll.flatten(collect(relationships(path))) as rels
WITH apoc.coll.toSet([n in nodes WHERE n is not null 
            | { id: id(n),label: labels(n),type:"",metadata: properties(n)  } ]) as nodes,
     apoc.coll.toSet([r in rels WHERE r is not null 
            | { id: id(r),source: id(startNode(r)),relation: type(r),target: id(endNode(r)), directed: "true"  } ]) as rels

RETURN { graph: { type:"",label: "",directed: "true",nodes: nodes,edges: rels,
         metadata:{ countNodes: size(nodes),countEdges: size(rels) } } } as graph;
person Michael Hunger    schedule 02.03.2017
comment
Это фантастика - спасибо. Настолько чище и передайте количество уровней, которые я хочу теперь искать в качестве параметра. Единственная проблема в том, что он возвращает несколько объектов графика на путь. Вы знаете, как с помощью этого запроса я могу возвращать только отдельные узлы и отношения. - person n4nite; 02.03.2017
comment
Мне все еще нужно выпустить apoc с apoc.coll.flatten - person Michael Hunger; 03.03.2017

Почему бы вам просто не использовать MATCH, и не будет пропущенных значений, поскольку вы ничего не делаете, если не найдете

MATCH (l0) <-[r1]- (l1) <-[r2]- (l2) <-[r3]- (l3)
WHERE ID(l0) = 65

Если вы хотите, вы можете выполнить необязательное сопоставление и фильтровать, как это

OPTIONAL MATCH (l0) <-[r1]- (l1) <-[r2]- (l2) <-[r3]- (l3)
WHERE ID(l0) = 65
WITH * where r3 is not null
Do sth
person Tomaž Bratanič    schedule 02.03.2017
comment
Если есть узлы с 1 или 2 ребрами, но нет узлов на расстоянии 3 ребер, я хочу, чтобы возвращались узлы с 1 или 2 ребрами. Вот почему я добавил OPTIONAL, который возвращает то, что мне нужно, но затем нарушает процедуру apoc, которую я использую для форматирования данных. - person n4nite; 02.03.2017
comment
Это ошибка, он должен уметь обрабатывать нулевые значения. А пока вы можете использовать coalesce. - person Michael Hunger; 02.03.2017