如何在TypeORM v0.3.10中递归查询实体的子节点
解决方案:TypeORM v0.3.10 递归加载所有子节点(含自身)
方法一:使用TypeORM Tree实体(推荐)
你的实体目前缺少Tree相关装饰器配置,补充后可直接借助内置方法实现递归查询:
1. 修改实体定义
import { Entity, PrimaryGeneratedColumn, Column, Tree, TreeParent, TreeChildren } from "typeorm"; import { TableNamesConstants } from "./your-path"; // 替换为实际路径 @Entity(TableNamesConstants.GROUPS) @Tree("closure-table") // 采用闭包表模式,适配递归查询场景 export class Group { @PrimaryGeneratedColumn() id: number; @Column('int', { nullable: true }) parentId?: number; @TreeParent() // 标记父节点关联 @ManyToOne(() => Group, { nullable: true, onDelete: "CASCADE" }) @JoinColumn({ name: 'parentId' }) parent?: Group; @TreeChildren() // 标记子节点集合 children: Group[]; }
注意:使用闭包表模式需先运行迁移命令,TypeORM会自动生成对应的
group_closure闭包表。
2. 查询所有子节点(含自身)
通过TreeRepository的findDescendants方法,直接获取当前节点及所有层级的子节点:
import { getRepository } from "typeorm"; import { Group } from "./your-path"; async function getGroupAndAllDescendants(groupId: number) { const treeRepository = getRepository(Group).extend({}); const group = await treeRepository.findOne({ where: { id: groupId } }); if (!group) return []; // 获取当前节点及所有后代 const descendants = await treeRepository.findDescendants(group); // 提取ID列表 return descendants.map(item => item.id); } // 调用示例 getGroupAndAllDescendants(1).then(ids => console.log(ids)); // 输出 [1,2,3] getGroupAndAllDescendants(2).then(ids => console.log(ids)); // 输出 [2,3]
方法二:使用原生SQL CTE(公共表表达式)
若Tree实体模式不适用,可直接用递归CTE编写原生查询,通过TypeORM QueryBuilder执行:
import { getConnection } from "typeorm"; import { Group } from "./your-path"; async function getGroupAndAllDescendants(groupId: number) { const result = await getConnection() .createQueryBuilder() .withRecursive("cte", () => { return this.select("id", "parentId") .from(Group, "g") .where("g.id = :groupId", { groupId }) .unionAll( this.select("child.id", "child.parentId") .from(Group, "child") .innerJoin("cte", "parent", "parent.id = child.parentId") ); }) .select("c.id") .from("cte", "c") .getRawMany(); // 提取ID列表 return result.map(item => item.id); } // 调用示例 getGroupAndAllDescendants(1).then(ids => console.log(ids)); // 输出 [1,2,3] getGroupAndAllDescendants(2).then(ids => console.log(ids)); // 输出 [2,3]
注意:需确保你的数据库版本支持递归CTE(如MySQL 8.0+、PostgreSQL等)。
常见问题排查
- 使用Tree实体查询为空时,检查是否已运行迁移生成闭包表,以及实体关联配置是否正确。
- 使用CTE时,确认传入的groupId存在,且数据库兼容递归语法。
内容的提问来源于stack exchange,提问作者Yoshi
相关产品推荐
相关产品推荐

