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

MongoDB聚合查询:关联Companies与Projects集合并嵌套项目数组

问题描述

我有两个MongoDB集合:Companies和Projects,需要编写聚合函数实现两个需求:

  1. 筛选出status为"Client"的公司
  2. 将与公司_id匹配的Projects文档以对象数组形式嵌套到公司文档新增的projects字段中

示例集合数据

Companies集合

{ 
  _id: ObjectId('2341908342'),
  companyName: "Meta",
  address: "123 Facebook Lane",
  status: "Client"
}

Projects集合

{
  _id: ObjectId('234123840'),
  companyId: '2341908342',
  name: "Test Project",
  price: 97450,
}
{
  _id: ObjectId('23413456'),
  companyId: '2341908342',
  name: "Test Project 2",
  price: 100000,
}

期望聚合结果

{
  _id: ObjectId('2341908342'),
  companyName: "Meta",
  address: "123 Facebook Lane",
  projects: [
    {
      _id: ObjectId('234123840'),
      companyId: '2341908342',
      name: "Test Project",
      price: 97450,
    },
    {
      _id: ObjectId('23413456'),
      companyId: '2341908342',
      name: "Test Project 2",
      price: 100000,
    }
  ]
}

现有问题

我尝试用$lookup实现,但返回的公司信息正确,projects数组始终为空,现有代码如下:

try {
const allClients = await companyCollection
  .aggregate([
    {
      $match: {
        orgId: {
          $in: [new ObjectId(req.user.orgId)],
        },
        status: {
          $in: ["Client"],
        },
      },
    },
    {
      $lookup: {
        from: "projects",
        let: {
          companyId: {
            $toString: [req.user.companyId],
          },
        },
        pipeline: [
          {
            $match: {
              $expr: {
                $eq: ["$companyId", "$$companyId"],
              },
            },
          },
        ],
        as: "projects",
      },
    },
  ])
  .toArray()
问题原因与修复方案

你的代码里$lookup的let部分存在核心错误:用了req.user.companyId(当前登录用户的公司ID)而非当前遍历的客户公司文档的_id来关联项目,导致匹配逻辑完全偏离需求。

修复后的聚合代码

try {
const allClients = await companyCollection
  .aggregate([
    {
      $match: {
        orgId: new ObjectId(req.user.orgId), // $in单个值可简化为直接匹配
        status: "Client" // $in单个值同样可简化
      },
    },
    {
      $lookup: {
        from: "projects",
        let: {
          // 将当前公司文档的ObjectId类型_id转为字符串,匹配Projects中字符串类型的companyId
          companyIdStr: { $toString: "$_id" }
        },
        pipeline: [
          {
            $match: {
              $expr: {
                $eq: ["$companyId", "$$companyIdStr"]
              }
            }
          }
        ],
        as: "projects"
      }
    }
  ])
  .toArray()
} catch (err) {
  console.error(err) // 建议添加错误处理逻辑
}

关键修复点

  1. 关联字段修正:let中必须引用当前公司文档的_id(即$_id),而非与业务无关的req.user.companyId
  2. 类型匹配处理:由于Projects集合的companyId是字符串类型,而Companies的_id是ObjectId类型,必须通过$toString转换类型后再匹配
  3. 条件简化:当$in仅包含单个值时,直接使用等于匹配更简洁高效

可选简化写法(仅适用于Projects的companyId为ObjectId类型)

如果Projects集合的companyId字段是ObjectId类型,可使用更简洁的$lookup写法:

{
  $lookup: {
    from: "projects",
    localField: "_id",
    foreignField: "companyId",
    as: "projects"
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 11:30:55