MongoDB聚合框架问题:如何按Aisle统计不同产品数量
MongoDB聚合统计每个货架(Aisle)下的不同产品数量
问题场景
订单数据结构示例:
{"_id": {"$oid": "60af57782fbbe971834ae2a6"},"order_id": 2539329,"user_id": 1,"order_number": 1,"order_dow": 2,"order_hour_of_day": 8,"products": [{"product_id": 196,"product_name": "Soda","aisle_id": 77,"aisle": "soft drinks","department_id": 7,"department": "beverages","add_to_cart_order": 1},{"product_id": 12427,"product_name": "Original Beef Jerky","aisle_id": 23,"aisle": "popcorn jerky","department_id": 19,"department": "snacks","add_to_cart_order": 3},{"product_id": 14084,"product_name": "Organic Unsweetened Vanilla Almond Milk","aisle_id": 91,"aisle": "soy lactosefree","department_id": 16,"department": "dairy eggs","add_to_cart_order": 2},{"product_id": 26088,"product_name": "Aged White Cheddar Popcorn","aisle_id": 23,"aisle": "popcorn jerky","department_id": 19,"department": "snacks","add_to_cart_order": 4},{"product_id": 26405,"product_name": "XL Pick-A-Size Paper Towel Rolls","aisle_id": 54,"aisle": "paper goods","department_id": 17,"department": "household","add_to_cart_order": 5}]}
需求是统计每个Aisle下的不同产品数量,但原聚合管道执行失败:
db.orders.aggregate([{"$unwind": "$products"},{"$group": {"_id": {"p_id": "$products.product_id", "p_name": "$products.product_name"}}},{"$project": {"products.aisle_id": 1, "products.aisle": 1}},{"$group": {"_id": {"a_id": "$products.aisle_id", "a_name": "$products.aisle"}, "prod per aisle": {"$sum": 1}}}])
错误原因
第一次$group阶段后,输出文档仅保留了_id(包含产品ID和名称),丢失了products字段及其中的aisle信息,后续$project无法读取不存在的products.aisle_id和products.aisle,导致最终分组无效。
正确实现方式
方式一:先去重产品再按货架统计
通过两次分组,先确保同一产品在同一货架下仅保留一条记录,再按货架统计数量:
db.orders.aggregate([ // 展开products数组,将每个产品转为独立文档 {"$unwind": "$products"}, // 按「产品+货架」维度分组,实现产品去重 {"$group": { "_id": { "product_id": "$products.product_id", "product_name": "$products.product_name", "aisle_id": "$products.aisle_id", "aisle": "$products.aisle" } }}, // 按货架分组,统计不同产品数量 {"$group": { "_id": { "aisle_id": "$_id.aisle_id", "aisle": "$_id.aisle" }, "distinct_product_count": {"$sum": 1} }}, // 可选:调整输出格式,优化可读性 {"$project": { "_id": 0, "aisle_id": "$_id.aisle_id", "aisle_name": "$_id.aisle", "distinct_product_count": 1 }} ])
方式二:用$addToSet收集去重产品再统计
利用$addToSet自动去重的特性,直接按货架收集所有不重复的产品ID,再通过$size计算数量:
db.orders.aggregate([ // 展开products数组 {"$unwind": "$products"}, // 按货架分组,收集该货架下所有不重复的产品ID {"$group": { "_id": {"aisle_id": "$products.aisle_id", "aisle": "$products.aisle"}, "distinct_product_ids": {"$addToSet": "$products.product_id"} }}, // 计算产品ID集合的大小,即为不同产品数量 {"$project": { "_id": 0, "aisle_id": "$_id.aisle_id", "aisle_name": "$_id.aisle", "distinct_product_count": {"$size": "$distinct_product_ids"} }} ])
两种方式都能实现需求,方式二更简洁高效,适合大多数场景。
内容的提问来源于stack exchange,提问作者Carlo
相关产品推荐
相关产品推荐

