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

如何编写MongoDB查询关联嵌套数据并生成父子关系列表

MongoDB集合关联与父子关系列表生成方案

问题背景

现有两个MongoDB集合:

  • 集合A(蓝色):内部节点(非外层)携带_parentNode属性;外层节点携带_organisationId,需关联集合B的某一层级(层级未知),自带kind属性。
  • 集合B(黑色):结构与A类似,内部节点携带_parentOrg属性,外层节点无关联属性,无kind属性(需默认设为Organisation)。

需求:生成包含完整父子关系的列表,格式示例如下:

[
  {
    "_id": { "$oid": "1" },
    "name": "A Inc",
    "children": [{"$oid": "2"}, {"$oid": "3"}],
    "kind": "Organisation"
  },
  ...
]

现有代码的问题

当前代码仅分别对两个集合执行graphLookup后拼接,存在两个核心问题:

  1. 未过滤根节点,导致每个节点都被作为根节点生成树结构,产生大量重复数据;
  2. 未处理集合A外层节点与集合B的关联逻辑,不符合需求中“关联B某一层级”的要求。

修正后的解决方案

步骤1:处理集合B,生成完整的组织树

先筛选B的根节点(无_parentOrg的节点),再通过graphLookup获取其完整子树,并添加默认kind属性:

// 处理集合B:获取根节点及其完整子树
let orgs = db.B.aggregate([
  // 仅保留B的根节点(无_parentOrg属性)
  { $match: { _parentOrg: { $exists: false } } },
  {
    $graphLookup: {
      from: "B",
      startWith: "$_id",
      connectFromField: "_id",
      connectToField: "_parentOrg",
      as: "children",
    },
  },
  {
    $project: {
      name: 1,
      children: "$children._id", // 仅保留子节点的ObjectID
      kind: { $literal: "Organisation" } // 为B添加默认kind属性
    }
  }
]).toArray();

步骤2:处理集合A,生成节点树并关联到B

筛选A的根节点(带_organisationId的节点),获取其完整子树,再将这些根节点关联到B中对应的节点下:

// 处理集合A:获取根节点及其子树,保留关联ID
let nodes = db.A.aggregate([
  // 仅保留A的外层根节点(带_organisationId属性)
  { $match: { _organisationId: { $exists: true } } },
  {
    $graphLookup: {
      from: "A",
      startWith: "$_id",
      connectFromField: "_id",
      connectToField: "_parentNode",
      as: "children",
    },
  },
  {
    $project: {
      name: 1,
      kind: 1, // 保留A自带的kind属性
      children: "$children._id",
      _organisationId: 1 // 保留关联B的ID
    }
  }
]).toArray();

// 将A的根节点挂载到B的对应节点下
nodes.forEach(node => {
  const targetOrg = orgs.find(org => org._id.equals(node._organisationId));
  if (targetOrg) {
    // 确保children数组存在
    targetOrg.children = targetOrg.children || [];
    targetOrg.children.push(node._id);
  }
});

// 合并结果:包含B的完整树,以及未找到对应B节点的A根节点
const finalResult = [...orgs, ...nodes.filter(node => !orgs.some(org => org._id.equals(node._organisationId)))];

关键说明

  • 通过$match过滤根节点,避免生成重复的树结构;
  • 利用_id.equals()方法对比MongoDB的ObjectID(直接===无法正确匹配);
  • 对未找到对应B节点的A根节点,直接加入最终结果,避免数据丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:23:21