You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Prisma递归关联查询如何获取Group模型下全层级子分组数据?

Prisma自关联模型全层级子分组查询方案

首先纠正你的推测:该单层返回结果并非Prisma的无限循环保护机制,只是include: { Subgroups: true }默认仅加载第一层关联数据,该限制完全可以突破,可根据业务场景选择以下三种实现方案:


方案1:固定层级嵌套include

适用于提前知道分组最大层级的场景,写法最简单,直接嵌套声明需要加载的Subgroups深度即可:

// 示例为加载3层级子分组,可根据实际业务调整嵌套深度
GroupModel.findFirst({
  where: { id: _id },
  include: {
    Subgroups: {
      include: {
        Subgroups: {
          include: {
            Subgroups: true
          }
        }
      }
    }
  }
});
  • 优点:无需额外逻辑,代码改动量最小
  • 缺点:仅支持固定深度的查询,无法适配层级不确定的场景

方案2:递归查询拼装数据

适用于分组层级不确定的场景,通过递归函数批量查询所有层级子分组后拼装为树结构:

async function getGroupWithAllSubgroups(groupId) {
  // 查询当前层级分组基础信息及直属子分组
  const group = await GroupModel.findFirst({
    where: { id: groupId },
    include: { Subgroups: true }
  });
  // 递归终止条件:分组不存在/没有子分组
  if (!group || group.Subgroups.length === 0) return group;
  // 递归遍历所有子分组,加载其下级分组
  group.Subgroups = await Promise.all(
    group.Subgroups.map(subgroup => getGroupWithAllSubgroups(subgroup.id))
  );
  return group;
}

// 调用方法
const fullGroupTree = await getGroupWithAllSubgroups(_id);
  • 优点:支持任意深度的递归查询,无需提前感知分组层级
  • 缺点:会发起多次数据库查询请求,分组量级较大时性能损耗明显

方案3:原生SQL递归查询(性能最优)

适用于数据量级较大的场景,通过数据库原生支持的递归CTE(公用表表达式)一次查询拿到所有层级分组数据,再自行转换为嵌套结构即可,以下为PostgreSQL语法示例:

const flatGroupList = await GroupModel.$queryRaw`
  WITH RECURSIVE GroupHierarchy AS (
    -- 锚点查询:匹配目标根分组
    SELECT id, "parentId" -- 可补充其他需要返回的Group字段
    FROM "Group"
    WHERE id = ${_id}
    UNION ALL
    -- 递归查询:匹配所有子层级分组
    SELECT g.id, g."parentId"
    FROM "Group" g
    INNER JOIN GroupHierarchy gh ON g."parentId" = gh.id
  )
  SELECT * FROM GroupHierarchy;
`;

查询结果为扁平化的全量分组列表,自行编写树结构转换函数即可得到嵌套格式的分组树。

  • 优点:仅发起一次数据库查询,性能最优,支持任意深度查询
  • 缺点:需要编写原生SQL,不同数据库的递归CTE语法存在细微差异,需要适配当前使用的数据库类型

内容的提问来源于stack exchange,提问作者Hugo Bois

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 17:54:03