如何在 Spring Data Neo4j 中获取节点及其所有 children

How to fetch nodes and all their children in Spring Data Neo4j

我有这个 Neo4j 节点 class:

@Node
@Data
@AllArgsConstructor
public class Person {

    @Id
    @GeneratedValue
    private Long id;
    
    private Long parentId;
        
    @Relationship(type = "PARENT_OF", direction = Relationship.Direction.OUTGOING)
    private List<Person> children;
    
    public Person addChild(Person person) {
        person.setParentId(this.id);
        this.children.add(person);
        return this;
    }
    
}

我想构建一个查询以与 Spring Data @Query 注释一起使用,以获取系谱树列表,其中根的 parentId 为空。对于每个根,我还想获取他们的 children,对于每个 child 他们自己的 children,等等

到目前为止,我能想到的最好的是:

public interface PersonRepository extends Neo4jRepository<Person, Long> {
    
    @Query("""
        MATCH (person:Person) 
        WHERE person.parentId IS NULL
        OPTIONAL MATCH (person)-[parentOf:PARENT_OF]->(children) 
        RETURN person, collect(parentOf), collect(children) 
        SKIP 0 
        LIMIT 10
    """)
    List<Person> findAllGenealogicalTrees();
}

但它似乎没有做我正在寻找的事情,因为它似乎只获取根的 children,而不是 [=] 的 children 34=]仁.

我的查询有问题吗?

编辑:

尝试了建议的查询:

MATCH path=(person)-[parentOf:PARENT_OF*]->(child)
WHERE person.parentId IS NULL
      AND NOT (child)-[:PARENT_OF]->()
RETURN path

但结果列表似乎如下:

Person(id=0, parentId=null, children=[Person(id=1, parentId=0, children=[Person(id=3, parentId=1, children=[])])])
Person(id=1, parentId=0, children=[Person(id=3, parentId=1, children=[])])
Person(id=3, parentId=1, children=[])

我只期待第一条记录,因为 parentId 应该为空。为什么它会返回另外两个具有非空 parentId 的记录?

要获取所有路径,可以使用变长模式

MATCH path=(person)-[parentOf:PARENT_OF*]->(child)
WHERE person.parentId IS NULL
      AND NOT (child)-[:PARENT_OF]->()
RETURN path

我认为我们可以同意,第一个查询本质上只进行一次跳跃,因为您使用 (person)-[parentOf:PARENT_OF]->(children) 明确表示您只想找到直接子项。

@Graphileon 给出的建议进入了正确的方向,但从其 return 部分仅提供了一组无序的节点和关系。 Spring Data Neo4j 只能假定所有人物都具有相同的重要性,因此 return 是所有人物的集合。

我的建议是继续使用基于路径的方法,但以 Spring Data Neo4j 和您同意的方式修改 return 语句 ;)

MATCH path=(person)-[:PARENT_OF*]->(child:Person)
WHERE person.parentId IS NULL
RETURN person, collect(nodes(path)), collect(relationships(path))

参考:https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#custom-queries.for-relationships.long-paths

另一种方法也可能是您在存储库中使用所谓的派生查找器方法:

List<Person> findAllByParentIdIsNull();

或者如果你想要它 pageable(不要忘记一些排序,否则数据可能会 return 随机编辑):

Page<Person> findAllByParentIdIsNull(Pageable pageable);

这将创建内部查询生成器,它将使用多个级联查询对数据进行探索性搜索(非基于路径的查询)。

在做出决定时(通常)有几点需要牢记:

  1. 如果您有很多跃点和分支导致响应时间相对较慢,那么基于路径的方法确实会增加数据库中的内存使用量。我认为这对您上面的域不会有问题,但这始终是我会关注的问题。
  2. 在这两种情况下(基于路径或级联查询),您最终都会得到三个数据桶:根节点、所有关系和所有相关节点。映射需要一些时间,因为 Spring Data Neo4j 必须将每个 returned 关系与它想要映射的每个关系的正确相关节点匹配。这没有任何问题,但具有循环映射域的结果。