Neo4 Hierachy Traversal

Rua*_*uan 3 neo4j

我有一些存储在neo4j中的分层数据,需要一个查询来查找特定用户的父节点的所有子节点.基本情景是:

(Root Task {control: 1})
    (Child Task 2 {control: 2})
    (Child Task 3 {control: 3})
        (Child Task 4 {control: 4})
Run Code Online (Sandbox Code Playgroud)

子任务与父项具有:CHILD_OF关系.所以这一切都很好,我能够得到父母的孩子.使用以下查询我将返回Child Task 4.

MATCH (rootTask:Task {control: 3}), (user:User {control: 60})
,(childTask:Task)-[:CHILD_OF*]->(rootTask)
WHERE (user)-[:LINKED_TO]->(childTask)
RETURN childTask
Run Code Online (Sandbox Code Playgroud)

问题在于用户需要重新安排结构,但仅限于他自己.所以我介绍了一个新的关系,其中包含对用户的引用.CHILD_OF_已添加,如果存在,则应优先于CHILD_OF关系.

因此,如果用户60决定(子任务4)任务应该属于(根任务)而不是(子任务3),则创建两个链接:

MERGE (Level 4 task)-[:CHILD_OF]->(Child Task 3)
MERGE (Level 4 task)-[:CHILD_OF_60]->(Root Task)
Run Code Online (Sandbox Code Playgroud)

他的观点现在基本上是:

(Root Task {control: 1})
    (Child Task 2 {control: 2})
    (Child Task 3 {control: 3})
    (Child Task 4 {control: 4})
Run Code Online (Sandbox Code Playgroud)

所以现在当我要求(孩子任务3)的孩子时,对于用户60我不想要(孩子任务4)返回.

使用先前的查询并添加用户特定关系和附加约束以不返回子任务如果它具有到未绑定任务的用户特定链接几乎可以工作,则期望它将返回(子任务4)的子项,因为它们只有与之相关的CHILD_OF关系.排除具有用户特定链接的childTask的逻辑也存在缺陷,因为它实际上可能指向同一个父级.

MATCH (rootTask:Task {control: 3}), (user:User {control: 60})
,(childTask:Task)-[:CHILD_OF|CHILD_OF_60*]->(rootTask)
WHERE (user)-[:LINKED_TO]->(childTask) 
AND NOT (childTask)-[:CHILD_OF_60]-(:Task)
RETURN childTask
Run Code Online (Sandbox Code Playgroud)

我需要的逻辑的本质是,如果关系存在关系CHILD_OF_60,则遵循该关系并忽略默认的CHILD_OF关系.

非常感谢您的帮助.经过相当多的搜索,我没有找到类似的场景.


测试数据

MERGE (ruan :User {control: 50, fullname: 'Ruan'})
MERGE (amber :User {control: 60, fullname: 'Amber'})
MERGE (task1 :Task {control: 1, subject: 'Root Task:'})
MERGE (task2 :Task {control: 2, subject: 'Child of Root:'})
MERGE (task3 :Task {control: 3, subject: 'User properties'})
MERGE (task4 :Task {control: 4, subject: 'User parent links'})
MERGE (task5 :Task {control: 5, subject: 'Hierarchy Traversal'})
MERGE (task6 :Task {control: 6, subject: 'Parent'})
MERGE (task7 :Task {control: 7, subject: 'Child'})
MERGE (task8 :Task {control: 8, subject: 'Query1'})
MERGE (task2)-[:CHILD_OF]->(task1)
MERGE (task3)-[:CHILD_OF]->(task2)
MERGE (task4)-[:CHILD_OF]->(task2)
MERGE (task5)-[:CHILD_OF]->(task2)
MERGE (task6)-[:CHILD_OF]->(task5)
MERGE (task7)-[:CHILD_OF]->(task5)
MERGE (task8)-[:CHILD_OF]->(task7)
MERGE (ruan)-[:LINKED_TO]->(task1)
MERGE (ruan)-[:LINKED_TO]->(task2)
MERGE (ruan)-[:LINKED_TO]->(task3)
MERGE (ruan)-[:LINKED_TO]->(task4)
MERGE (ruan)-[:LINKED_TO]->(task5)
MERGE (ruan)-[:LINKED_TO]->(task6)
MERGE (ruan)-[:LINKED_TO]->(task7)
MERGE (ruan)-[:LINKED_TO]->(task8)
MERGE (amber)-[:LINKED_TO]->(task1)
MERGE (amber)-[:LINKED_TO]->(task2)
MERGE (amber)-[:LINKED_TO]->(task3)
MERGE (amber)-[:LINKED_TO]->(task4)
MERGE (amber)-[:LINKED_TO]->(task5)
MERGE (amber)-[:LINKED_TO]->(task6)
MERGE (amber)-[:LINKED_TO]->(task7)
MERGE (amber)-[:LINKED_TO]->(task8)
MERGE (task2)-[:CHILD_OF]->(task1)
MERGE (task3)-[:CHILD_OF]->(task2)
MERGE (task4)-[:CHILD_OF]->(task2)
MERGE (task5)-[:CHILD_OF]->(task2)
MERGE (task6)-[:CHILD_OF]->(task5)
MERGE (task7)-[:CHILD_OF]->(task5)
MERGE (task8)-[:CHILD_OF]->(task7)
MERGE (task5)-[:CHILD_OF_60]->(task1)
MERGE (task3)-[:CHILD_OF_60]->(task1)
Run Code Online (Sandbox Code Playgroud)

Bri*_*ood 5

这是一个有趣的工作.我在这里组建了一个GraphGist来证明我的建议:

http://graphgist.neo4j.com/#!/gists/54d8b5ef8cfb85197aa4

但我也会在这里提出解决方案:

MATCH
  (rootTask:Task { control: 1 }),
  path=(childTask:Task)-[:CHILD_OF|CHILD_OF_60*1..]->rootTask,
  (user:User { control: 60 })-[:LINKED_TO]->childTask
WITH childTask, path AS the_path, path
UNWIND nodes(path) AS node
OPTIONAL MATCH node-[:CHILD_OF_60]->(otherParent:Task)
WITH childTask, the_path, collect(otherParent IS NULL OR otherParent IN nodes(the_path))[0..-1] AS otherParentResults
WHERE ALL(result IN otherParentResults WHERE result)
RETURN DISTINCT childTask
Run Code Online (Sandbox Code Playgroud)

基本上我正在获取路径,通过CHILD_OF_60关系检查叶子节点是否有另一个父节点,然后如果它没有另一个父节点或者如果otherParent不在祖先路径中则返回子节点.

如果它得到自动化测试的支持,我会对这个解决方案感到更舒服,但试一试!;)

此外,作为一项规则,我尽量不做变量关系名称.您可能需要考虑user_id在您的CHILD_OF关系中使用可选属性.或者,您可能拥有类似CHILD_OF_FOR_USER具有user_id属性的关系类型.

编辑:我已经编辑了上面的查询和GraphGist来处理在根节点的路径中移动了祖先的子节点