Можно ли добавить временное свойство к neo4j node только для возврата?

Я использовал cypher и neo4j какое-то время, и я снова и снова сталкиваюсь с подобной проблемой.

Я хотел бы иметь возможность добавить временное свойство к node, которое существует только в возвращаемых данных и не сохраняется в базе данных Neo4j.

Например, текущая проблема, над которой я работаю, дается N-арная древовидная структура в базе данных графа, я хотел бы вернуть детей определенного node, и информационное логическое значение, дающее мне знать, что у этих детей есть дети.

Запрос на получение этой информации достаточно прост:

MATCH (parent:Item { guid: "Identifier here" })-[:HASCHILD]->(child:Item)
OPTIONAL MATCH (child)-[:HASCHILD]->(grandchild:Item)
WITH parent, child, LENGTH(COLLECT(grandchild)) > 0 AS has_children

Теперь у меня есть родительский, дочерний и логический, дающий мне знать, что есть еще дети.

То, что я хотел бы сделать дальше, - установить has_children boolean как свойство на дочерних узлах, но только для возврата запроса мне не нужно, чтобы свойство сохранялось.

Я знаю, что есть некоторые решения, чтобы получить то, что я ищу, но ни один из них не является тем, что я ищу.

1) Я мог бы создать временный node: (Продолжение из предыдущего запроса)

...
WITH parent, child, LENGTH(COLLECT(grandchild)) > 0 AS haschildren,
{
    childkey1: child.childkey1,
    childkey2: child.childkey2,
    ...
    has_children: haschildren
} AS tempnode
RETURN parent, tempnode

Это решение не очень велико, вам нужно знать точный тип node и все свойства node, с которыми вы имеете дело, он не будет работать в общем случае.

2) Я мог бы УСТАНОВИТЬ и УДАЛИТЬ логическое, временно сохраняя его в базе данных (как описано в Neo4J создать временную переменную в Cypher).

Это не очень удобно, так как это приведет к многократной записи db (для добавления и удаления). Кроме того, он не так динамичен, как вариант 1, поскольку он сможет обрабатывать только простые типы. (Вариант 1 может обрабатывать более сложные случаи, такие как добавление коллекции узлов вместо простого логического).

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

Что-то вдоль линий

 WITH parent, child, LENGTH(COLLECT(grandchild)) > 0 AS haschildren,
 TEMPSET child.has_children = haschildren

Обратите внимание, что я немного упростил приведенные примеры. Я столкнулся с этой проблемой несколько раз в разных контекстах в neo4j. В большинстве случаев я либо иду с вариантом 1, либо строю правильную структуру после обработки на стороне приложения после возвращения запроса.

Есть ли лучший способ?

Ответ 1

Вы можете попробовать вернуть карту. Взгляните в этом примере:

// Creating a sample node    
CREATE (:Person {name:'Jon', id: 1})

Возврат проекции с дополнительным булевым:

MATCH (p:Person {id:1})
WITH p, true AS has_children
RETURN p{.*, has_children:has_children}

Результат:

╒═════════════════════════════════════════╕
│"p"                                      │
╞═════════════════════════════════════════╡
│{"id":1,"name":"Jon","has_children":true}│
└─────────────────────────────────────────┘

Вышеприведенный запрос возвращает все свойства p node с дополнительным булевым.

Ответ 2

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

Смотрите https://neo4j.com/docs/labs/apoc/current/virtual/, а также https://community.neo4j.com/t/virtual-nodes-and-relationships-use-case/110. См. https://neo4j.com/docs/labs/apoc/current/introduction/ для установки и т.д. Apoc.

По сути, вы создаете временные (виртуальные) копии узлов, к которым вы хотите добавить свойства, а также временные (виртуальные) отношения, связывающие их с существующими или другими виртуальными узлами.

Например. чтобы в user-> групповых отношениях мы могли добавить новое свойство для пользователей и счетчик для таких отношений (протестировано с Neo4j v3.5):

MATCH (user:User)-[r:MEMBER_OF]-(team:Team)
WITH user, r, team, count(*) AS count
CALL apoc.create.vNode(labels(user), user{.*, something:'new'})
    YIELD node AS vUser
CALL apoc.create.vRelationship(vUser, type(r), r{.*,count}, team)
    YIELD rel AS vr
RETURN vUser, team, vr

Или, например, что-то вроде этого (не проверено):

MATCH (parent:Item { guid: "Identifier here" })-[r:HASCHILD]->(child:Item)
OPTIONAL MATCH (child)-[:HASCHILD]->(grandchild:Item)
WITH parent, child, LENGTH(COLLECT(grandchild)) > 0 AS has_children
CALL apoc.create.vNode(labels(child), child{.*, has_children:has_children})
    YIELD node AS vChild
CALL apoc.create.vRelationship(parent, type(r), r{.*}, vChild)
    YIELD rel AS vr
RETURN parent, vChild, vr