Cypher-запрос для перемещения узлов из одной структуры списка в другую - PullRequest
0 голосов
/ 11 марта 2020

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

enter image description here

Я ищу способ создания запроса, который перемещает узел из списка, на который указывает связь VALID_INVITATIONS, в другой список, указанный на INVALID_INVITATIONS. Перемещенный узел должен быть установлен первым в новом списке.

Я нашел рабочее решение, но из-за нехватки знаний и опыта в Cypher, я прошу вас, сообщество, о помощи и улучшениях для него. Как вы увидите, существует много императивных кодовых «взломов» (CASE WHEN) вместо декларативных, как должно было бы быть Cypher. Буду признателен за все советы и подсказки

MATCH (u:User)
MATCH (u)-[:VALID_INVITATIONS|PREVIOUS*]->(current:Invitation{ id:3 })

//find (current) node's predecessor which might pointing on it through VALID_INVITATIONS or PREVIOUS relationships
OPTIONAL MATCH (u)-[oldValidRel:VALID_INVITATIONS]->(current)
OPTIONAL MATCH (predecessor:Invitation)-[oldPredecessorRel:PREVIOUS]->(current)
//find (current) node's subsequent node
OPTIONAL MATCH (current)-[oldSubsequentRel:PREVIOUS]->(subsequent:Invitation)

//first we re-create connections in list pointed by VALID_INVITATION relationship for consistency
WITH *, CASE subsequent WHEN NULL THEN [] ELSE [1] END AS hasSubsequent

//if (current) node is connected to (u) User we replace VALID_INVITATIONS relationship
FOREACH(_ IN CASE oldValidRel WHEN NULL THEN [] ELSE [1] END |
    DELETE oldValidRel

    //if (subsequent) node exist then we need to re-link it
    FOREACH(_ IN hasSubsequent |
        MERGE (u)-[:VALID_INVITATIONS]->(subsequent)
        DELETE oldSubsequentRel
    )
)

//following condition should be XOR with the one above (only one must be executed)
//if (current) node has another Invitation node as predecessor in list
FOREACH(_ IN CASE oldPredecessorRel WHEN NULL THEN [] ELSE [1] END | 
    DELETE oldPredecessorRel

    //if (subsequent) node exist then we need to re-link it
    FOREACH(_ IN hasSubsequent |
        MERGE (predecessor)-[:PREVIOUS]->(subsequent)
        DELETE oldSubsequentRel
    )
)

WITH u, current

//now it is time to move (current) node to beginning of the list pointed by  INVALID_INVITATIONS relationship
MERGE (u)-[:INVALID_INVITATIONS]->(current)
WITH u, current
//find obsolete oldRel:INVALID_INVITATIONS relationship
MATCH (current)<-[:INVALID_INVITATIONS]-(u)-[oldRel:INVALID_INVITATIONS]->(oldInv)
DELETE oldRel
//link (current) with previously "first" node in INVALID_INVITATIONS list
MERGE (current)-[:PREVIOUS]->(oldInv)

1 Ответ

0 голосов
/ 13 марта 2020

После некоторого "веселья" и помощи от @ cybersam я пришел к более короткому решению:

MATCH (u:User)-[:VALID_INVITATIONS|PREVIOUS*]->(current:Invitation {id:4})
MATCH (predecessor)-[oldPredecessorRel:VALID_INVITATIONS|PREVIOUS]->(current)
OPTIONAL MATCH (current)-[oldSubsequentRel:PREVIOUS]->(subsequent)

CALL apoc.do.when(subsequent IS NOT NULL, "CALL apoc.create.relationship($p, $r, NULL, $s) YIELD rel RETURN rel", "", {p:predecessor, r:type(oldPredecessorRel), s:subsequent}) YIELD value

DELETE oldPredecessorRel, oldSubsequentRel

WITH u, current
MERGE (u)-[:INVALID_INVITATIONS]->(current)
WITH u, current
MATCH (oldInv)<-[oldRel:INVALID_INVITATIONS]-(u)-[:INVALID_INVITATIONS]->(current)
DELETE oldRel
MERGE (current)-[:PREVIOUS]->(oldInv)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...