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

如何在Mongoose中为文档添加基于前置文档求和的新字段?

问题描述

需要将集合按日期排序后,为每个文档添加一个新字段sum,其值为当前文档及之前所有文档的value字段之和(第一个文档的sum为自身value,后续文档依次累加前置所有条目),用于生成折线图的累计数据。

输入示例

// 集合中的原始文档
{ type: 'typeX', date: '01-01-2000', value: 10 }
{ type: 'typeY', date: '01-03-2000', value: -5 }
{ type: 'typeX', date: '01-02-2000', value: 3 }
{ type: 'typeX', date: '01-03-2000', value: -1 }
{ type: 'typeY', date: '01-01-2000', value: 10 }

输出示例

{ type: 'typeX', date: '01-01-2000', value: 10, sum: 10}
{ type: 'typeY', date: '01-01-2000', value: 10, sum: 10}
{ type: 'typeX', date: '01-02-2000', value: 3, sum: 13}
{ type: 'typeY', date: '01-03-2000', value: -5, sum: 5}
{ type: 'typeX', date: '01-03-2000', value: -1, sum: 12}

能否通过Mongoose的aggregate或其他方式实现该需求?


解决方案

完全可以通过Mongoose的聚合管道实现,推荐使用MongoDB 5.0及以上版本支持的窗口函数,语法简洁且性能高效。

实现代码

const result = await YourModel.aggregate([
  // 第一步:转换字符串日期为Date类型,按日期升序排序
  {
    $sort: {
      $dateFromString: {
        dateString: "$date",
        format: "%d-%m-%Y" // 匹配输入的DD-MM-YYYY日期格式
      }: 1
    }
  },
  // 第二步:用窗口函数计算累计求和
  {
    $setWindowFields: {
      sortBy: {
        $dateFromString: {
          dateString: "$date",
          format: "%d-%m-%Y"
        }: 1
      },
      output: {
        sum: {
          $sum: "$value",
          window: {
            documents: ["unbounded", "current"] // 窗口范围:从第一个文档到当前文档
          }
        }
      }
    }
  }
]);

代码说明

  1. $sort阶段:输入的date是字符串格式(DD-MM-YYYY),直接按字符串排序会导致顺序错误,因此用$dateFromString转换为标准Date类型后再排序,确保日期从早到晚的顺序正确。
  2. $setWindowFields阶段:核心逻辑,通过定义窗口范围(集合起始到当前文档),用$sum对窗口内的value字段进行累计求和,结果存入新字段sum。

旧版本MongoDB兼容方案(低于5.0)

如果MongoDB版本低于5.0,无法使用窗口函数,可通过以下方式实现:

const result = await YourModel.aggregate([
  // 添加日期对象字段用于排序
  {
    $addFields: {
      dateObj: {
        $dateFromString: {
          dateString: "$date",
          format: "%d-%m-%Y"
        }
      }
    }
  },
  { $sort: { dateObj: 1 } },
  // 将所有文档合并为数组
  {
    $group: {
      _id: null,
      docs: { $push: "$$ROOT" }
    }
  },
  // 遍历数组计算累计和
  {
    $project: {
      docs: {
        $map: {
          input: "$docs",
          as: "doc",
          in: {
            $mergeObjects: [
              "$$doc",
              {
                sum: {
                  $sum: {
                    $slice: ["$docs.value", 0, { $add: [{ $indexOfArray: ["$docs._id", "$$doc._id"] }, 1] }]
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  // 展开数组回到单个文档
  { $unwind: "$docs" },
  // 移除临时字段,还原原结构
  { $replaceRoot: { newRoot: { $omit: ["$$ROOT.docs.dateObj"] } } }
]);

该方案性能低于窗口函数,数据量大时会有明显延迟,建议优先升级MongoDB版本使用窗口函数方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 04:52:43