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

如何将单集合中多文档合并为单个文档?(基于文档引用一对多模型)

处理文档引用型一对多关系的聚合合并方案

别着急,我来帮你搞定文档引用型一对多关系的聚合合并问题!咱们先拿个实际场景的例子来说,这样你能更快对应到自己的业务上。

假设你有两个集合:

  • authors(主集合,存储作者信息)
  • articles(子集合,存储文章,通过author_id引用作者的_id)

示例集合数据

authors集合文档:

{
  "_id": ObjectId("60d21b4667d0d8992e610c85"),
  "name": "Jane Doe",
  "email": "jane@example.com"
}

articles集合文档:

{
  "_id": ObjectId("60d21b8967d0d8992e610c86"),
  "title": "MongoDB Aggregation Basics",
  "content": "入门级聚合操作指南...",
  "author_id": ObjectId("60d21b4667d0d8992e610c85")
}
{
  "_id": ObjectId("60d21b9d67d0d8992e610c87"),
  "title": "Document References vs Embedding",
  "content": "两种数据模型的优劣对比...",
  "author_id": ObjectId("60d21b4667d0d8992e610c85")
}

场景1:将子文档合并到主文档中(作者+关联文章列表)

如果你的目标是生成包含所有关联文章的作者文档,比如这样的结果:

{
  "_id": ObjectId("60d21b4667d0d8992e610c85"),
  "name": "Jane Doe",
  "email": "jane@example.com",
  "articles": [
    {
      "title": "MongoDB Aggregation Basics",
      "content": "入门级聚合操作指南..."
    },
    {
      "title": "Document References vs Embedding",
      "content": "两种数据模型的优劣对比..."
    }
  ]
}

可以用$lookup(关联集合)+$project(过滤冗余字段)的聚合管道:

db.authors.aggregate([
  // 第一步:关联articles集合,匹配author_id和authors._id,把结果存入articles数组
  {
    $lookup: {
      from: "articles",       // 要关联的子集合名
      localField: "_id",      // 主集合的关联字段
      foreignField: "author_id", // 子集合的关联字段
      as: "articles"          // 存储关联结果的字段名
    }
  },
  // 第二步:过滤掉不需要的冗余字段(可选)
  {
    $project: {
      "articles.author_id": 0, // 去掉文章里的author_id(已经关联上了,不需要保留)
      "articles._id": 0        // 如果不需要文章的_id,也可以去掉
    }
  }
])

场景2:将主文档信息合并到子文档中(文章+关联作者信息)

如果你的需求是反过来,给每篇文章带上对应的作者信息,目标结果如下:

{
  "_id": ObjectId("60d21b8967d0d8992e610c86"),
  "title": "MongoDB Aggregation Basics",
  "content": "入门级聚合操作指南...",
  "author": {
    "name": "Jane Doe",
    "email": "jane@example.com"
  }
}

可以用$lookup+$unwind(展开数组)+$project的组合:

db.articles.aggregate([
  // 第一步:关联authors集合
  {
    $lookup: {
      from: "authors",
      localField: "author_id",
      foreignField: "_id",
      as: "author"
    }
  },
  // 第二步:把$lookup返回的数组(只会有一个匹配项)展开成单个对象
  {
    $unwind: "$author"
  },
  // 第三步:过滤冗余字段
  {
    $project: {
      author_id: 0,          // 去掉原有的author_id字段
      "author._id": 0        // 去掉作者的_id(如果不需要)
    }
  }
])

进阶场景:添加统计信息(比如作者的文章数量)

如果需要在合并文档的同时添加统计字段(比如每个作者的文章总数),可以加上$addFields步骤:

db.authors.aggregate([
  {
    $lookup: {
      from: "articles",
      localField: "_id",
      foreignField: "author_id",
      as: "articles"
    }
  },
  // 添加文章数量统计字段
  {
    $addFields: {
      article_count: { $size: "$articles" } // 用$size计算数组长度
    }
  },
  {
    $project: {
      "articles.author_id": 0
    }
  }
])

几个关键注意事项

  • 版本兼容性:$lookup是MongoDB 3.2及以上版本支持的,确保你的数据库版本符合要求。
  • 性能优化:给子集合的关联字段(比如articles.author_id)创建索引,能大幅提升$lookup的查询速度。
  • 空关联处理:如果某个主文档没有对应的子文档,$lookup会返回空数组。你可以用$match过滤掉这类文档,或者用$ifNull给空数组设置默认值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:54:19