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

如何用MongoDB的$aggregate按时间段分组发票数据并求和?

MongoDB按时间段分组汇总发票数据解决方案

需求说明

将发票数据按0-10天、11-20天、>20天的时间段分组,汇总每个时间段对应的value总和,使用MongoDB聚合管道实现。

示例数据

[
  {
    '_id': '1',
    'value': 10,
    'due_date': '20221001'
  },
  {
    '_id': '2',
    'value': 10,
    'due_date': '20221012'
  },
  {
    '_id': '3',
    'value': 10,
    'due_date': '20221030'
  }
]

期望结果

[
  {
    "_id": "0-10 days",
    "total": 10
  },
  {
    "_id": "11-20 days",
    "total": 10
  },
  {
    "_id": ">20 days",
    "total": 10
  }
]

问题分析

你之前使用$facet的写法没有实现需求,核心问题是未正确处理日期格式转换、日期差计算,也没有设置符合要求的时间段分组逻辑。

正确聚合管道实现

以下是完整的聚合步骤,针对字符串格式的due_date做了适配:

  1. 转换日期格式:将字符串类型的due_date(如20221001)转为MongoDB可识别的日期类型
  2. 计算天数差:算出当前日期与due_date的间隔天数
  3. 标记时间段:根据天数差判断数据所属的分组区间
  4. 分组求和:按时间段分组,汇总value的总和

完整聚合代码(MongoDB Shell)

db.invoices.aggregate([
  // 转换due_date为日期类型
  {
    $addFields: {
      dueDate: {
        $dateFromString: {
          dateString: "$due_date",
          format: "%Y%m%d"
        }
      }
    }
  },
  // 计算当前日期与dueDate的天数差
  {
    $addFields: {
      daysDiff: {
        $floor: {
          $divide: [
            { $subtract: [new Date(), "$dueDate"] },
            1000 * 60 * 60 * 24 // 毫秒转天数
          ]
        }
      }
    }
  },
  // 标记所属时间段
  {
    $addFields: {
      timeRange: {
        $switch: {
          branches: [
            { case: { $and: [{ $gte: ["$daysDiff", 0] }, { $lte: ["$daysDiff", 10] }] }, then: "0-10 days" },
            { case: { $and: [{ $gte: ["$daysDiff", 11] }, { $lte: ["$daysDiff", 20] }] }, then: "11-20 days" }
          ],
          default: ">20 days"
        }
      }
    }
  },
  // 按时间段分组求和
  {
    $group: {
      _id: "$timeRange",
      total: { $sum: "$value" }
    }
  },
  // 可选:按时间段排序
  {
    $sort: { _id: 1 }
  }
])

PHP环境适配(使用Carbon)

如果是在PHP中使用MongoDB扩展,代码调整如下:

$pipeline = [
    // 转换日期格式
    [
        '$addFields' => [
            'dueDate' => [
                '$dateFromString' => [
                    'dateString' => '$due_date',
                    'format' => '%Y%m%d'
                ]
            ]
        ]
    ],
    // 计算天数差
    [
        '$addFields' => [
            'daysDiff' => [
                '$floor' => [
                    '$divide' => [
                        ['$subtract' => [new MongoDB\BSON\UTCDateTime(), '$dueDate']],
                        1000 * 60 * 60 * 24
                    ]
                ]
            ]
        ]
    ],
    // 标记时间段
    [
        '$addFields' => [
            'timeRange' => [
                '$switch' => [
                    'branches' => [
                        [
                            'case' => ['$and' => [['$gte' => ['$daysDiff', 0]], ['$lte' => ['$daysDiff', 10]]]],
                            'then' => '0-10 days'
                        ],
                        [
                            'case' => ['$and' => [['$gte' => ['$daysDiff', 11]], ['$lte' => ['$daysDiff', 20]]]],
                            'then' => '11-20 days'
                        ]
                    ],
                    'default' => '>20 days'
                ]
            ]
        ]
    ],
    // 分组求和
    [
        '$group' => [
            '_id' => '$timeRange',
            'total' => ['$sum' => '$value']
        ]
    ],
    // 排序
    [
        '$sort' => ['_id' => 1]
    ]
];

// 执行聚合查询
$result = $collection->aggregate($pipeline);

关键说明

  • $dateFromString:指定格式%Y%m%d,将字符串日期转为MongoDB日期类型
  • 日期差计算:通过$subtract得到毫秒差后,除以一天的毫秒数得到天数,$floor取整避免小数干扰
  • $switch:覆盖所有天数区间的判断逻辑,确保每条数据都能分到对应组
  • $group:按标记的时间段分组,用$sum完成数值汇总

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 07:15:40