MongoDB聚合:按产品分组数组元素的实现问题
MongoDB聚合分组调整:按月份+产品统计状态计数
原始数据格式
[ { "_id":{ "month":"Jan", "year":"2022" }, "products":[ { "product":"ProdA", "status":"failed", "count":15 }, { "product":"ProdA", "status":"success", "count":5 }, { "product":"ProdB", "status":"failed", "count":20 }, { "product":"ProdB", "status":"success", "count":10 } ] }, // 更多类似月份数据 ]
期望输出格式
[ { "_id":{ "month":"Jan", "year":"2022" }, "products":[ { "product":"ProdA","status":[{"name":"success","count":5},{"name":"failed","count":15}] }, { "product":"ProdB","status":[{"name":"success","count":10},{"name":"failed","count":20}] } ] }, // 后续月份数据 ]
尝试的聚合查询
db.collection.aggregate([{ $unwind: "$products" }, { $group: { "_id": { month: "$_id.month", year: "$_id.year" }, products: { $push: { "product": "$product", status: { $push: { name: "$status", count: "$count" } } } } } }]);
问题分析与解决方案
你的查询问题在于:在顶层$group中直接嵌套$push生成status数组是无效的,$push不能在$group的字段定义里嵌套使用。要实现期望结构,需要分两层分组:
正确的聚合步骤
- 先用
$unwind展开products数组,将每个产品状态条目转为独立文档; - 第一层分组:按
年月+产品名称聚合,收集每个产品的所有状态数据; - 第二层分组:按
年月聚合,重组同一月份下的所有产品数据。
完整聚合代码
db.collection.aggregate([ // 展开products数组,拆分每个状态条目为独立文档 { $unwind: "$products" }, // 第一级分组:按年月+产品名聚合,生成每个产品的status数组 { $group: { "_id": { month: "$_id.month", year: "$_id.year", product: "$products.product" }, status: { $push: { name: "$products.status", count: "$products.count" } } } }, // 第二级分组:按年月聚合,重组products数组 { $group: { "_id": { month: "$_id.month", year: "$_id.year" }, products: { $push: { product: "$_id.product", status: "$status" } } } } ])
步骤说明
- $unwind阶段:将原文档中products数组的每个元素拆分为单独文档,确保后续分组能精准定位到每个产品的状态条目;
- 第一级$group:以
年月+产品名为分组键,把同一产品的不同状态数据收集到status数组中,完成单个产品的状态聚合; - 第二级$group:以
年月为分组键,将同一月份下的所有产品数据(包含已聚合的status数组)合并到products数组,最终得到符合要求的结构。
内容的提问来源于stack exchange,提问作者NodeFriend
相关产品推荐
相关产品推荐

