У меня есть иерархия объектов, которые могут иметь отношение к разным типам узлов на разных уровнях. Я пытаюсь запросить один указанный узел c с его отношениями к другому типу узла, а также список его дочерних узлов с их отношениями к другому типу узла. И я хочу подсчитать все различное количество узлов другого типа.
Вот запрос, который работает, но подсчитывает только узлы type2, связанные с объектом верхнего уровня:
MATCH(root:Type1{id: {id}})-[:PARENT_OF*]->(child:Type1)-[:USES*]->(other2:Type2)
WITH root, child, collect(other2) as other2list, count(other2) as other2count
WITH root, collect(child {.*, otherCount: other2count, other: other2list}) as children
OPTIONAL MATCH (root)-[:USES*]->(other1:Type2)
RETURN root {.*, arm: collect(other1), otherCount: count(other1), children}
Это дает мне именно то, что я ожидаю: один результат, содержащий иерархию с root вверху, список его объектов Type2 и список его дочерних элементов, каждый со своим списком объектов Type2.
Однако я хочу, чтобы otherCount root отсчитывал все объекты Type2, независимо от того, подключены они к root или к любому из его дочерних элементов. Простое добавление отсчетов не сработает, потому что я не хочу считать дубликаты. (Не волнуйтесь, я знаком с DISTINCT
; просто исключаю его из этого запроса для целей тестирования.)
Поэтому я пытаюсь передать коллекцию объектов Type2, связанных с дочерними элементами, чтобы сосчитайте их:
MATCH(root:Type1{id: {id}})-[:PARENT_OF*]->(child:Type1)-[:USES*]->(other2:Type2)
WITH root, child, collect(other2) as other2list, count(other2) as other2count
WITH root, collect(child {.*, otherCount: other2count, other: other2list}) as children, other2list
OPTIONAL MATCH (root)-[:USES*]->(other1:Type2)
RETURN root {.*, arm: collect(other1), otherCount: count(DISTINCT other1+other2list), children}
Теперь я неожиданно получаю несколько строк. Я подозреваю, что это как-то вызвано передачей other2list во втором предложении WITH
, но как еще я смогу подсчитать эти объекты?
Есть ли способ сделать это в Cypher?
РЕДАКТИРОВАТЬ: Причина, по которой я не рассчитываю other2count ранее, заключается в том, что я хочу отсеять дубликаты с other1. (Я просто добавил DISTINCT
, чтобы прояснить это.)
Итак, у меня была идея: чтобы предотвратить раннюю группировку (как указано @cybersam ниже), я попытался собрать другие2 списки. Вот так:
MATCH(root:Type1{id: {id}})-[:PARENT_OF*]->(child:Type1)-[:USES*]->(other2:Type2)
WITH root, child, collect(other2) as other2list, count(other2) as other2count
WITH root, collect(child {.*, otherCount: other2count, other: other2list}) as children, collect(other2list) as other2lists
OPTIONAL MATCH (root)-[:USES*]->(other1:Type2)
RETURN root {.*, arm: collect(other1), otherCount: count(DISTINCT other1+other2lists), children}
Это ломает браузер. В какой-то момент мне удалось получить странно искаженный результат от некоторого изменения этого, которое заняло более 9000 мс. Не знаю, почему это такая проблема, но я думаю, что упаковка их в список списков и последующая распаковка этого списка должны быть частью решения.