NEO4层次结构遍历



我有一些层次结构数据存储在neo4j中,需要查询以找到特定用户的父节点的所有孩子。基本情况是:

(Root Task {control: 1})
    (Child Task 2 {control: 2})
    (Child Task 3 {control: 3})
        (Child Task 4 {control: 4})

子任务与父母有:CHILD_OF的关系。所以这一切都很好,我能够找到父母的孩子。使用以下查询,我会返回子任务4。

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

问题出在用户重新安排结构,但仅针对他自己。因此,我引入了一种新的关系,其中包含对用户的参考。添加了CHILD_OF_<usercontrol>,如果存在,则应优先于CHILD_OF关系。

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

MERGE (Level 4 task)-[:CHILD_OF]->(Child Task 3)
MERGE (Level 4 task)-[:CHILD_OF_60]->(Root Task)

他的观点基本上是:

(Root Task {control: 1})
    (Child Task 2 {control: 2})
    (Child Task 3 {control: 3})
    (Child Task 4 {control: 4})

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

使用先前的查询并添加用户特定关系,以及如果子任务具有用户特定链接到未结合任务几乎有效,则不返回任务,预计它将返回(儿童任务4),因为他们只有一个链接的child_of关系。排除具有用户特定链接的儿童任务的逻辑也存在缺陷,因为它实际上可能指向同一父母。

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

我需要的逻辑的本质是,如果存在关系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)

这是一个有趣的工作。我在这里编造了一个图形学家,以演示我的建议:

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

基本上,我正在走路,检查叶子节点是否通过CHILD_OF_60关系有另一个父母,然后如果孩子没有其他父母,或者是否没有其他父母,或者其他父母不在祖先路径中。

如果通过自动测试支持该解决方案,我会更舒服,但请尝试一下!;)

另外,通常,我尽量不制作可变关系名称。您可能需要考虑在CHILD_OF关系上具有可选的user_id属性。另外,您可能具有具有user_id属性的CHILD_OF_FOR_USER关系类型之类的东西。

编辑:我已经编辑了上面的查询和Graphgist,以照顾带有移动祖先的子节点的儿童节点。

最新更新