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

MongoDB中不同类型对象数组的分组求和问题

问题分析

你当前的做法会出问题,核心原因是:$unwind拆分sections数组后,每个拆分出的文档只包含department、location、salary三者中的一个。分组时MongoDB会把带department和location的文档归为一组(但这组没有薪资数据,求和结果为0),把仅带salary的文档单独归为另一组,最终得到两个不符合预期的结果。

解决方案

正确的思路是先将同一份文档里的department、location、salary整合到同一层级,再进行分组汇总。以下提供两种实现方式:

方式一:用$filter提取目标字段

db.collection.aggregate([
  // 第一步:从sections数组中分别筛选出department、location、salary对应的section
  {
    $addFields: {
      deptSection: {
        $arrayElemAt: [
          { $filter: {
              input: "$sections",
              cond: { $exists: ["$$this.categoryData.department", true] }
            }
          },
          0
        ]
      },
      locSection: {
        $arrayElemAt: [
          { $filter: {
              input: "$sections",
              cond: { $exists: ["$$this.categoryData.location", true] }
            }
          },
          0
        ]
      },
      salarySection: {
        $arrayElemAt: [
          { $filter: {
              input: "$sections",
              cond: { $exists: ["$$this.categoryData.salary", true] }
            }
          },
          0
        ]
      }
    }
  },
  // 第二步:提取嵌套字段,简化后续分组操作
  {
    $addFields: {
      department: "$deptSection.categoryData.department",
      location: "$locSection.categoryData.location",
      salaryAmount: "$salarySection.categoryData.salary.amount"
    }
  },
  // 第三步:按department和location分组,汇总薪资
  {
    $group: {
      _id: {
        deptId: "$department.id",
        deptName: "$department.name",
        locId: "$location.id",
        locName: "$location.name"
      },
      totalSalary: { $sum: "$salaryAmount" }
    }
  },
  // 第四步:整理输出格式
  {
    $project: {
      _id: 0,
      department: { id: "$_id.deptId", name: "$_id.deptName" },
      location: { id: "$_id.locId", name: "$_id.locName" },
      totalSalary: 1
    }
  }
])

方式二:用$reduce合并字段(更简洁)

db.collection.aggregate([
  // 第一步:遍历sections数组,合并所有categoryData到同一对象
  {
    $addFields: {
      mergedData: {
        $reduce: {
          input: "$sections",
          initialValue: {},
          in: { $mergeObjects: ["$$value", "$$this.categoryData"] }
        }
      }
    }
  },
  // 第二步:按department和location分组,汇总薪资
  {
    $group: {
      _id: {
        deptId: "$mergedData.department.id",
        deptName: "$mergedData.department.name",
        locId: "$mergedData.location.id",
        locName: "$mergedData.location.name"
      },
      totalSalary: { $sum: "$mergedData.salary.amount" }
    }
  },
  // 第三步:整理输出格式
  {
    $project: {
      _id: 0,
      department: { id: "$_id.deptId", name: "$_id.deptName" },
      location: { id: "$_id.locId", name: "$_id.locName" },
      totalSalary: 1
    }
  }
])

两种方式最终都会得到如下结果:

{
  "department": { "id": 1, "name": "english" },
  "location": { "id": 1, "name": "US" },
  "totalSalary": 240000
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 18:13:23