MongoDB如何对文档数组按id分组聚合计算score平均值并更新state字段
MongoDB 文档处理:数组分组求平均 + 根字段修改
要实现你需要的文档转换,用MongoDB的聚合框架就能搞定,下面是完整的实现代码和分步解释:
完整聚合查询
db.collection.aggregate([ // 更新根文档_id中的state字段 { $addFields: { _id: { $mergeObjects: ["$_id", { state: "New York" }] } } }, // 展开List数组,便于逐个处理元素 { $unwind: "$List" }, // 分组计算每个id对应的score平均值 { $group: { _id: { rootId: "$_id", itemId: "$List.id", itemName: "$List.name" }, avgScore: { $avg: "$List.score" } } }, // 重新组装成目标文档结构 { $group: { _id: "$_id.rootId", List: { $push: { id: "$_id.itemId", score: "$avgScore", name: "$_id.itemName" } } } } ])
分步解释每个阶段
- $addFields 阶段:用
$mergeObjects把原_id对象和新的state值合并,既替换了state为"New York",又保留了原有的st字段,不用手动重新写整个_id结构。 - $unwind 阶段:把
List数组拆成单个文档,这样每个数组元素都能独立参与后续的分组计算——毕竟MongoDB的分组操作是针对文档级别的,不展开的话没法直接对数组内元素分组。 - 第一个$group 阶段:我们需要同时按「根文档的
_id」「数组元素的id」「数组元素的name」来分组(确保同一个id对应的name不会出错),然后用$avg计算该组的score平均值。 - 第二个$group 阶段:重新以根文档的
_id为分组依据,用$push把每个分组的结果重新组装成List数组,还原成你需要的最终文档结构。
可选优化(如果name和id一一对应)
如果能确定同一个id对应的name完全一致(比如你的业务逻辑保证这点),可以简化第一个$group的分组键,用$first来获取name,减少分组维度:
// 替换第一个$group阶段 { $group: { _id: { rootId: "$_id", itemId: "$List.id" }, avgScore: { $avg: "$List.score" }, itemName: { $first: "$List.name" } } }
然后第二个$group里的name就用$itemName即可,这样效率会稍高一些。
内容的提问来源于stack exchange,提问作者Vineet
相关产品推荐
相关产品推荐

