如何基于集合字段值与另一集合键实现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....
相关产品推荐
相关产品推荐

