MongoDB聚合:分组并推送多属性问题求助
MongoDB聚合实现按ID合并卡片与终端金额统计
正确的聚合管道实现
以下是能得到你期望结果的聚合管道:
db.collection.aggregate([ // 分三个维度并行处理:终端统计、卡片统计、基础信息汇总 { $facet: { "terminal_stats": [ // 筛选有终端类型的文档 { $match: { terminal_type: { $exists: true } } }, // 按ID+终端类型分组,统计每个终端的金额 { $group: { _id: { id: "$id", type: "$terminal_type" }, amount: { $sum: "$amount" } } }, // 按ID分组,收集该ID下的所有终端统计 { $group: { _id: "$_id.id", terminals: { $push: { name: "$_id.type", amount: "$amount" } } } } ], "card_stats": [ // 筛选有卡片信息的文档 { $match: { card: { $exists: true } } }, // 按ID+卡片ID分组,统计每张卡片的总金额 { $group: { _id: { id: "$id", card_id: "$card.id" }, card_name: { $first: "$card.name" }, amount: { $sum: "$amount" } } }, // 按ID分组,收集该ID下的所有卡片统计 { $group: { _id: "$_id.id", cards: { $push: { id: "$_id.card_id", name: "$card_name", amount: "$amount" } } } } ], "base_info": [ // 按ID分组,汇总基础名称和总金额 { $group: { _id: "$id", name: { $first: "$name" }, total_amount: { $sum: "$amount" } } } ] } }, // 展开基础信息文档,方便后续合并 { $unwind: "$base_info" }, // 匹配当前ID对应的终端和卡片统计数据 { $addFields: { matched_terminals: { $arrayElemAt: [ { $filter: { input: "$terminal_stats", cond: { $eq: ["$$this._id", "$base_info._id"] } } }, 0 ] }, matched_cards: { $arrayElemAt: [ { $filter: { input: "$card_stats", cond: { $eq: ["$$this._id", "$base_info._id"] } } }, 0 ] } } }, // 整理最终输出字段,空数据用空数组填充 { $project: { _id: 0, id: "$base_info._id", name: "$base_info.name", amount: "$base_info.total_amount", terminals: { $ifNull: ["$matched_terminals.terminals", []] }, cards: { $ifNull: ["$matched_cards.cards", []] } } } ])
原管道的问题分析
你之前的分组逻辑错误地将终端类型和卡片ID绑定在同一个分组键中,导致终端统计被关联到具体卡片上,最后按ID合并时无法提取到该ID下的所有终端数据。此外,第二次分组后,同一个ID会对应多个卡片分组的文档,第三次分组时terminals字段分散在这些文档中,自然无法直接聚合。
关键思路说明
使用$facet可以并行处理三个独立的统计分支,避免分组逻辑互相干扰:
- terminal_stats:单独统计每个ID下各终端的金额总和
- card_stats:单独统计每个ID下各卡片的金额总和
- base_info:汇总每个ID的基础名称和总金额
最后通过匹配ID将三个分支的结果合并,得到完整的结构化数据。
内容的提问来源于stack exchange,提问作者nm94
相关产品推荐
相关产品推荐

