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

如何在MongoDB中用聚合查询计算数组元素的累计和?

如何在MongoDB聚合中计算数组内marks的累计和?

嘿,要计算你集合里每个学生result数组中marks的累计和,MongoDB的聚合框架里有几种实用的方法,我给你拆解一下:

方案一:通用版(适配所有支持聚合的MongoDB版本)

如果你的MongoDB版本比较旧,用$reduce配合$map就可以实现,它能遍历数组并逐步计算累计值,同时保留原数组的每个元素信息:

db.students.aggregate([
  {
    $addFields: {
      resultWithCumulative: {
        $reduce: {
          input: "$result",
          initialValue: {
            cumulativeSum: 0,
            items: []
          },
          in: {
            cumulativeSum: { $add: ["$$value.cumulativeSum", "$$this.marks"] },
            items: {
              $concatArrays: [
                "$$value.items",
                [
                  {
                    test: "$$this.test",
                    marks: "$$this.marks",
                    cumulativeMarks: { $add: ["$$value.cumulativeSum", "$$this.marks"] }
                  }
                ]
              ]
            }
          }
        }
      }
    }
  },
  {
    $project: {
      student: 1,
      result: "$resultWithCumulative.items"
    }
  }
])

步骤解释:

  • $addFields阶段:用$reduce遍历每个学生的result数组,初始化累计和为0、空数组存结果。每次迭代时,把当前元素的marks加到累计和上,再将包含原test、marks和当前累计值的对象存入结果数组。
  • $project阶段:整理输出结构,把计算后的数组替换回原来的result字段。

方案二:简洁版(MongoDB 5.0+适用)

如果你的MongoDB是5.0及以上版本,$setWindowFields窗口函数会让这个操作更简洁,它专门用来处理这类序列累计计算:

db.students.aggregate([
  { $unwind: "$result" },
  {
    $setWindowFields: {
      partitionBy: "$_id",
      sortBy: { "result.test": 1 }, // 这里的排序规则要根据你的业务需求调整,确保累计顺序正确
      output: {
        cumulativeMarks: {
          $sum: "$result.marks",
          window: { documents: ["unbounded", "current"] }
        }
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      student: { $first: "$student" },
      result: {
        $push: {
          test: "$result.test",
          marks: "$result.marks",
          cumulativeMarks: "$cumulativeMarks"
        }
      }
    }
  }
])

步骤解释:

  • $unwind:先把result数组拆分成单个文档,这样窗口函数才能逐个处理元素。
  • $setWindowFields:按学生的_id分组,按result.test排序(你可以换成其他字段,比如时间戳,只要符合你想要的累计顺序),然后计算从数组开头到当前元素的marks总和,作为cumulativeMarks。
  • $group:把拆分后的文档重新聚合回原结构,将每个元素和对应的累计值组装成新的result数组。

额外需求:只需要学生的总累计分?

如果不需要每个测试的累计,只想要每个学生所有marks的总和,那更简单:

db.students.aggregate([
  {
    $addFields: {
      totalCumulativeMarks: {
        $reduce: {
          input: "$result",
          initialValue: 0,
          in: { $add: ["$$value", "$$this.marks"] }
        }
      }
    }
  }
])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:50:05