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

如何基于集合字段值与另一集合键实现MongoDB Lookup并统计数量

MongoDB集合关联统计方案(根据动态键匹配)

需求明确

根据collectionA的name字段,匹配collectionB中classNames的对应键,并统计符合条件(如student: true)的文档数量,以下是两种可行的聚合实现方案:


方案一:统计所有唯一name的匹配数量

如果需要先对collectionA的name去重,再统计每个name对应的匹配数,使用以下聚合管道:

db.collectionA.aggregate([
  // 提取collectionA中所有唯一的name
  {
    $group: {
      _id: null,
      uniqueNames: { $addToSet: "$name" }
    }
  },
  // 关联collectionB并处理动态键匹配统计
  {
    $lookup: {
      from: "collectionB",
      let: { names: "$uniqueNames" },
      pipeline: [
        // 将classNames对象转为数组,方便处理动态键
        {
          $addFields: {
            classList: { $objectToArray: "$classNames" }
          }
        },
        // 展开数组,逐个处理每个键值对
        { $unwind: "$classList" },
        // 匹配键名在uniqueNames中,且student为true的文档
        {
          $match: {
            $expr: {
              $and: [
                { $in: ["$classList.k", "$$names"] },
                { $eq: ["$classList.v.student", true] }
              ]
            }
          }
        },
        // 按name分组统计数量
        {
          $group: {
            _id: "$classList.k",
            matchedCount: { $sum: 1 }
          }
        }
      ],
      as: "nameStatistics"
    }
  },
  // 格式化输出结果
  { $unwind: "$nameStatistics" },
  {
    $project: {
      _id: 0,
      name: "$nameStatistics._id",
      matchedCount: "$nameStatistics.matchedCount"
    }
  }
])

输出示例:

{ "name": "A", "matchedCount": 1 },
{ "name": "B", "matchedCount": 2 }

方案二:为collectionA每个文档添加匹配数量

如果需要保留collectionA的原始文档结构,同时为每个文档添加对应name的统计数,使用以下聚合管道:

db.collectionA.aggregate([
  // 关联collectionB并统计当前name的匹配数
  {
    $lookup: {
      from: "collectionB",
      let: { currentName: "$name" },
      pipeline: [
        {
          $addFields: {
            classList: { $objectToArray: "$classNames" }
          }
        },
        { $unwind: "$classList" },
        {
          $match: {
            $expr: {
              $and: [
                { $eq: ["$classList.k", "$$currentName"] },
                { $eq: ["$classList.v.student", true] }
              ]
            }
          }
        },
        // 统计符合条件的文档总数
        { $count: "count" }
      ],
      as: "stats"
    }
  },
  // 处理统计结果(若没有匹配则显示0)
  {
    $addFields: {
      matchedCount: { $ifNull: [{ $arrayElemAt: ["$stats.count", 0] }, 0] }
    }
  },
  // 移除临时统计字段
  { $project: { stats: 0 } }
])

输出示例:

{ "_id": 001, "name": "A", "day": "sun", "matchedCount": 1 },
{ "_id": 001, "name": "B", "day": "Mon", "matchedCount": 2 }

关键说明

  • $objectToArray是核心:将classNames的动态键值对转为数组,解决MongoDB无法直接匹配动态键的问题。
  • 若不需要过滤student: true,只需删除$match中的{ $eq: ["$classList.v.student", true] }条件即可。
  • 若collectionB数据量较大,建议将classNames转为数组后建立索引,提升聚合性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 03:23:23