如何在MongoDB中根据元素属性将数组元素数据聚合到单个元素中
解决MongoDB嵌套数组按qId分组聚合的问题
嘿,我懂你这种卡壳的感觉——看起来你是想处理嵌套在qData数组里的、按qId分组的数据对吧?先把你的示例数据整理清楚,方便咱们看:
// 你的MongoDB文档示例 [ { "_id": ObjectId("5ad078cc43c90bb8118b457b"), "totalTime": 323, "qData": [ { "qId": "123456", "weight": 38 }, { "qId": "654321", "age": 21 }, { "qId": "123456", "age": 14 }, { "qId": "654321", "height": 122 }, { "qId": "654321", "weight": 34 } ] }, { "_id": ObjectId("5ad084cc43c90bb8118b4583"), "totalTime": 312, "qData": [ { "qId": "123456", "weight": 42 } // 省略的部分默认是同结构数据 ] } ]
我猜你大概率是想把所有qData里的元素按qId归类,聚合每个qId对应的所有属性值?下面给你两种常见场景的解决方案:
场景1:按qId聚合所有属性,相同属性值存为数组
这个方案会把同一个qId下的所有属性(比如weight、age)都收集起来,相同属性的多个值放到数组里:
db.yourCollection.aggregate([ // 拆分数组,把每个qData元素变成独立文档 { $unwind: "$qData" }, // 按qId分组,收集所有非qId的属性键值对 { $group: { _id: "$qData.qId", attributes: { $push: { $arrayToObject: { $filter: { input: { $objectToArray: "$qData" }, cond: { $ne: ["$$this.k", "qId"] } } } } } } }, // 把收集到的属性合并成清晰的结构,相同属性值用数组存储 { $project: { _id: 0, qId: "$_id", details: { $reduce: { input: "$attributes", initialValue: {}, in: { $mergeObjects: [ "$$value", { $arrayToObject: { $map: { input: { $objectToArray: "$$this" }, as: "attr", in: { k: "$$attr.k", v: { $concatArrays: [ { $ifNull: ["$$value.$$attr.k", []] }, ["$$attr.v"] ] } } } } } ] } } } } } ])
执行后你会得到类似这样的结果:
[ { "qId": "123456", "details": { "weight": [38, 42], "age": [14] } }, { "qId": "654321", "details": { "age": [21], "height": [122], "weight": [34] } } ]
场景2:按qId聚合特定属性的统计值(比如weight总和)
如果你的需求更具体,比如只想算每个qId的weight总和,同时收集age和height的值,可以用这个简化版:
db.yourCollection.aggregate([ { $unwind: "$qData" }, { $group: { _id: "$qData.qId", totalWeight: { $sum: { $ifNull: ["$qData.weight", 0] } }, ageList: { $push: { $ifNull: ["$qData.age", null] } }, heightList: { $push: { $ifNull: ["$qData.height", null] } } } }, // 整理输出结构,去掉默认的_id,换成qId { $project: { _id: 0, qId: "$_id", totalWeight: 1, ageList: 1, heightList: 1 } } ])
这个查询的结果会更简洁,适合有明确统计需求的场景。
要是你的需求不是这两种,随时补充细节,我再帮你调整!
内容的提问来源于stack exchange,提问作者JohnPan
相关产品推荐
相关产品推荐

