MongoDB按当前时间起始的15分钟间隔分组数据问题
基于当前时间偏移的MongoDB 15分钟分组问题分析与解决
问题说明
需要以当前时间为起始点按15分钟间隔对Stat_Snapshots集合分组(比如当前9:08,分组点为9:08、9:23、8:53、8:38等),但现有聚合查询只能按固定的整点15分(9:00、9:15、8:45等)分组,不符合需求。
现有聚合代码:
Stat_Snapshots.aggregate([ { $group: { _id: { "$toDate": { "$subtract": [ { "$toLong": "$date" }, { "$mod": [{ "$toLong": "$date" }, 1000 * 60 * 15] } ] } } , floorPrice: { "$min": "$floorPrice" }, listedCount: { "$min": "$listedCount" } }, } ])
原因分析
现有代码的逻辑是将每条数据的date时间戳减去其对15分钟毫秒数的模,得到的是最近的15分钟整点对齐时间(比如7:01归到7:00,7:16归到7:15),完全没有结合当前时间做偏移,因此分组始终是固定的整点15分间隔,无法实现基于当前时间的动态分组。
解决方案
核心思路是:计算每条数据时间与当前时间的差值,对15分钟取模后,用数据时间戳减去该模值,就能得到以当前时间为基准的15分钟分组起始点。
修改后的聚合代码(MongoDB 4.2+,支持$$NOW变量)
Stat_Snapshots.aggregate([ { $group: { _id: { $toDate: { $subtract: [ { $toLong: "$date" }, { $mod: [ // 计算数据时间与当前时间的差值(毫秒) { $subtract: [{ $toLong: "$date" }, { $toLong: "$$NOW" }] }, // 15分钟对应的毫秒数 1000 * 60 * 15 ] } ] } }, floorPrice: { $min: "$floorPrice" }, listedCount: { $min: "$listedCount" } } }, // 可选:按分组时间升序排序,便于查看结果 { $sort: { _id: 1 } } ])
逻辑说明
以当前时间为9:08(时间戳T)为例:
- 对于时间为9:01的记录:
- 差值
D-T= -7分钟(-420000毫秒) - MongoDB的
$mod对负数返回非负余数,即mod(-420000, 900000) = 480000(8分钟) - 分组时间戳 =
D - 480000=T - 15分钟= 8:53,该记录被分到8:53的分组
- 差值
- 对于时间为9:10的记录:
- 差值
D-T= 2分钟(120000毫秒) mod(120000, 900000) = 120000- 分组时间戳 =
D - 120000=T=9:08,该记录被分到9:08的分组
- 差值
这样所有记录都会被分到以当前时间为起始点、每15分钟间隔的分组中,完全符合需求。
验证结果
用提供的示例输入文档测试,若当前时间为2022-08-16T07:08:00.000Z,则:
- 所有
7:01的记录会被分到2022-08-16T06:53:00.000Z分组 7:16的记录会被分到2022-08-16T07:08:00.000Z分组7:31的记录会被分到2022-08-16T07:23:00.000Z分组
内容的提问来源于stack exchange,提问作者Gene Lim
相关产品推荐
相关产品推荐

