You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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可以并行处理三个独立的统计分支,避免分组逻辑互相干扰:

  1. terminal_stats:单独统计每个ID下各终端的金额总和
  2. card_stats:单独统计每个ID下各卡片的金额总和
  3. base_info:汇总每个ID的基础名称和总金额
    最后通过匹配ID将三个分支的结果合并,得到完整的结构化数据。

内容的提问来源于stack exchange,提问作者nm94

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 06:01:01