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

MongoDB同表左连接与organisations集合递归左连接技术需求

MongoDB 同表关联与递归层级查询实现方案

一、核心需求拆解

  • nodes集合同表左连接:A类型文档通过_b字段关联B类型文档的_id,需保留所有字段并区分重复属性(如name)
  • organisations集合递归查询:文档通过_parentOrg递归关联父级,层级未知,需获取所有父级并处理重复字段

二、示例数据准备

nodes集合数据

db.nodes.insertMany([
  { _id: ObjectId("60d21b4667d0d8992e610c85"), type: "A", name: "Node A1", _b: ObjectId("60d21b4667d0d8992e610c86"), org: ObjectId("60d21b4667d0d8992e610c8a") },
  { _id: ObjectId("60d21b4667d0d8992e610c86"), type: "B", name: "Node B1", org: ObjectId("60d21b4667d0d8992e610c8a") },
  { _id: ObjectId("60d21b4667d0d8992e610c87"), type: "A", name: "Node A2", _b: ObjectId("60d21b4667d0d8992e610c88"), org: ObjectId("60d21b4667d0d8992e610c8b") },
  { _id: ObjectId("60d21b4667d0d8992e610c88"), type: "B", name: "Node B2", org: ObjectId("60d21b4667d0d8992e610c8b") }
])

organisations集合数据

db.organisations.insertMany([
  { _id: ObjectId("60d21b4667d0d8992e610c8a"), name: "Org C1", _parentOrg: ObjectId("60d21b4667d0d8992e610c8c") },
  { _id: ObjectId("60d21b4667d0d8992e610c8b"), name: "Org C2", _parentOrg: null },
  { _id: ObjectId("60d21b4667d0d8992e610c8c"), name: "Parent Org 1", _parentOrg: ObjectId("60d21b4667d0d8992e610c8d") },
  { _id: ObjectId("60d21b4667d0d8992e610c8d"), name: "Top Parent Org", _parentOrg: null }
])

三、完整聚合查询实现

db.nodes.aggregate([
  // 1. 同表左连接A与关联的B类型文档
  {
    $lookup: {
      from: "nodes",
      localField: "_b",
      foreignField: "_id",
      as: "b_node"
    }
  },
  // 将关联的B文档数组转为单个对象(保留无关联的A文档)
  { $unwind: { path: "$b_node", preserveNullAndEmptyArrays: true } },
  // 2. 关联对应的组织(C)文档
  {
    $lookup: {
      from: "organisations",
      localField: "org",
      foreignField: "_id",
      as: "org_info"
    }
  },
  { $unwind: { path: "$org_info", preserveNullAndEmptyArrays: true } },
  // 3. 递归查询组织的所有父级
  {
    $graphLookup: {
      from: "organisations",
      startWith: "$org_info._parentOrg",
      connectFromField: "_parentOrg",
      connectToField: "_id",
      as: "parent_orgs"
    }
  },
  // 4. 重命名字段,区分A、B、C及父级的重复属性
  {
    $project: {
      // A类型节点字段
      a_id: "$_id",
      a_name: "$name",
      a_type: "$type",
      // B类型节点字段
      b_id: "$b_node._id",
      b_name: "$b_node.name",
      b_type: "$b_node.type",
      // 当前组织(C)字段
      c_id: "$org_info._id",
      c_name: "$org_info.name",
      // 父级组织列表,重命名重复字段
      parent_orgs: {
        $map: {
          input: "$parent_orgs",
          as: "parent",
          in: {
            parent_id: "$$parent._id",
            parent_name: "$$parent.name",
            parent_parentOrg: "$$parent._parentOrg"
          }
        }
      },
      // 按需保留其他原始字段
      original_fields: "$$ROOT"
    }
  }
])

四、关键步骤说明

  1. 同表左连接:使用$lookup时指定from: "nodes"实现同表关联,通过localField: "_b"和foreignField: "_id"匹配A与B类型文档,$unwind将关联结果数组转为单个对象,确保无关联的A文档不被过滤。
  2. 递归层级查询:使用MongoDB专属的$graphLookup处理递归关联,startWith指定递归起始点(当前组织的_parentOrg),connectFromField和connectToField定义递归关联规则,自动获取所有层级的父级组织。
  3. 重复字段区分:通过$project给不同来源的重复字段(如name)添加前缀(a_、b_、c_、parent_),避免字段覆盖冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:09:56