聚合日期函数是什么
聚合里的日期函数负责把时间戳转成统计维度:$dateToString 按格式化串输出可读日期,$dateTrunc 把时间截断到指定粒度(秒、分、时、天、周、月),$dateDiff 求两个时间之差,$dateAdd 与 $dateSubtract 做日期加减。按天、按小时的报表通用写法是把 $dateTrunc 或 $dateToString 的结果当作 $group 的 _id,再对指标求和计数。
基本信息
| 分组键写法 | { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: "$ts" } } } } |
|---|---|
| 粒度截断 | { $dateTrunc: { date: "$ts", unit: "hour" } } |
| 时区参数 | timezone 可写 "Asia/Shanghai" 或 "+08:00" |
| 默认时区 | 不写 timezone 按 UTC 计算,跨天统计会偏移 |
| 求差 | { $dateDiff: { startDate: "$a", endDate: "$b", unit: "second" } } |
典型使用场景
- 日活与趋势报表:按自然日分组计数,输出折线图数据
- 月度归档:$dateTrunc 到 month 得到月度汇总,供对账使用
- 履约时长统计:$dateDiff 算下单到发货之间的小时数
- 同比环比:用 $dateAdd 与 $dateSubtract 取去年同期的时间区间
- 补零与对齐:把时间桶作为维度,应用侧补齐空缺日期避免折线跳变
按自然日聚合
按自然日聚合
db.orders.aggregate([
{ $match: { ts: { $gte: ISODate("2026-01-01T00:00:00Z"), $lt: ISODate("2026-02-01T00:00:00Z") } } },
{ $group: {
_id: { $dateToString: { format: "%Y-%m-%d", date: "$ts", timezone: "+08:00" } }, // 东八区自然日
orders: { $sum: 1 },
total: { $sum: "$amount" }
} },
{ $sort: { _id: 1 } }
])
// 换成截断到小时,_id 是日期对象,可继续参与日期运算
// { $group: { _id: { $dateTrunc: { date: "$ts", unit: "hour", timezone: "+08:00" } } } }四个函数怎么选
| 表达式 | 返回 | 适用 |
|---|---|---|
| $dateToString | 格式化字符串 | 直接给前端展示的日期标签 |
| $dateTrunc | 日期对象 | 结果还要继续做日期运算时 |
| $dateDiff | 整数 | 算时长、账期天数 |
| $dateAdd / $dateSubtract | 日期对象 | 取上一周期做对比 |
不写 timezone 就按 UTC 计算,中国区报表会把凌晨 8 点前的数据算进前一天;报表口径应把时区固定在代码或配置里,避免各处写法不一致。
$dateTrunc 支持 week 与 month 粒度,但周起点规则与时区相关,跨系统对账前先对齐口径。
求时长与取上周期
求时长与取上周期
// 履约时长:下单到发货的小时数
{ $addFields: { hours: { $dateDiff: { startDate: "$created", endDate: "$shipTime", unit: "hour" } } } }
// 上月同期区间,用于环比
{ $match: { ts: {
$gte: { $dateSubtract: { startDate: "$$NOW", unit: "month", amount: 1 } },
$lt: "$$NOW"
} } }用 $$NOW 这类系统变量拿当前时刻时,整条管道只在开始执行时求值一次,适合做「最近 N 天」的口径,但结果会随执行时间变化,做报表快照时应改为传入固定时间参数。
$dateToString 的 format 除 %Y-%m-%d 外还支持 %H:%M:%S、ISO 周相关的格式符等,按官方格式符表选择;写错格式符通常得到字面输出而不是报错,上线前要先用几条真实数据验证。