MongoDB:如何从首个文档的createdAt按7天分组?及$dateTrunc疑问
问题分析与解决方案
问题2:$dateTrunc返回2022-10-29的原因
MongoDB的$dateTrunc并非以输入日期为基准往前推7天,而是从**纪元时间(1970-01-01)**开始,按指定的binSize(7天)划分固定时间桶,返回输入日期所在桶的起始时间。
计算验证:2022-11-02所在的7天桶区间是2022-10-29至2022-11-05(2022-10-29 + 7天),因此$dateTrunc返回该桶的起始时间2022-10-29,而非预期的2022-10-25。
问题1:实现动态往后7天分组的方案
$dateTrunc的固定分桶逻辑无法满足“以实际存在的文档日期为起点,往后7天内的文档归为一组”的需求,需要通过聚合管道结合窗口函数实现动态分组:
完整聚合代码
db.xxxx.aggregate([ // 按日期升序排序,确保文档顺序正确 { $sort: { orderDate: 1 } }, // 使用窗口函数计算每个文档的分组起始日期 { $setWindowFields: { partitionBy: null, // 全局处理所有文档 sortBy: { orderDate: 1 }, output: { groupStartDate: { $reduce: { input: "$orderDate", initialValue: { currentStart: { $first: "$orderDate" }, result: { $first: "$orderDate" } }, in: { $let: { vars: { // 当前分组的结束时间(起点+7天) groupEnd: { $add: ["$$value.currentStart", 7 * 24 * 60 * 60 * 1000] } }, in: { currentStart: { // 若当前文档日期超过分组结束时间,更新分组起点为当前日期 $cond: { if: { $gt: ["$$this", "$$groupEnd"] }, then: "$$this", else: "$$value.currentStart" } }, result: { $cond: { if: { $gt: ["$$this", "$$groupEnd"] }, then: "$$this", else: "$$value.result" } } } } } }, window: { documents: ["unbounded", "current"] } } } } }, // 按分组起始日期聚合文档 { $group: { _id: "$groupStartDate", documents: { $push: "$$ROOT" }, // 计算分组的结束日期(起点+7天) groupEndDate: { $max: { $add: ["$groupStartDate", 7 * 24 * 60 * 60 * 1000] } } } }, // 可选:格式化日期为字符串,便于阅读 { $project: { _id: 0, groupStartDate: { $dateToString: { format: "%Y-%m-%d", date: "$_id" } }, groupEndDate: { $dateToString: { format: "%Y-%m-%d", date: "$groupEndDate" } }, documents: 1 } } ])
逻辑说明
- 排序:先按日期升序排列文档,确保从最早的文档开始处理。
- 动态计算分组起点:通过
$setWindowFields和$reduce遍历每个文档,判断当前文档是否超出上一个分组的7天范围:- 若未超出,沿用之前的分组起点;
- 若超出,将当前文档的日期设为新的分组起点。
- 分组聚合:按计算出的分组起点聚合文档,同时计算每个分组的结束日期。
内容的提问来源于stack exchange,提问作者Chicky
相关产品推荐
相关产品推荐

