MongoDB聚合$group按小时分组及选取每组首个文档的实现思路
按小时分组并获取每组首个文档的MongoDB实现思路
这需求我日常工作里碰过好多次,给你两种实用的实现方案,根据你的MongoDB版本选就行:
方案一:聚合管道 + $group(推荐,简洁高效)
这种方法核心是先排序,再按小时分组,用$first累加器取每组的首个文档(如果要的是该小时内最早创建的文档,排序是关键)。
适合MongoDB 5.0+(支持$dateTrunc)
$dateTrunc可以直接把日期截断到小时单位,非常方便:
db.yourCollection.aggregate([ // 先按CreationDateTime升序排序,确保每组最早的文档排在最前面 { $sort: { CreationDateTime: 1 } }, { $group: { _id: { // 将日期截断到小时,同一小时的文档会被归为一组 hour: { $dateTrunc: { date: "$CreationDateTime", unit: "hour" } } }, // 取每组的第一个文档(排序后就是该小时最早创建的文档) firstDocument: { $first: "$$ROOT" } } }, // 可选:整理输出格式,让结果更易读 { $project: { _id: 0, hour: "$_id.hour", document: "$firstDocument" } } ])
适合MongoDB 5.0以下版本
如果你的MongoDB版本不支持$dateTrunc,可以用日期字段拆分组合的方式生成分组键:
db.yourCollection.aggregate([ { $sort: { CreationDateTime: 1 } }, { $group: { _id: { year: { $year: "$CreationDateTime" }, month: { $month: "$CreationDateTime" }, day: { $dayOfMonth: "$CreationDateTime" }, hour: { $hour: "$CreationDateTime" } }, firstDocument: { $first: "$$ROOT" } } }, // 把拆分的年月日小时重新拼成日期格式,方便查看 { $project: { _id: 0, hour: { $dateFromParts: { year: "$_id.year", month: "$_id.month", day: "$_id.day", hour: "$_id.hour" } }, document: "$firstDocument" } } ])
方案二:聚合管道 + $bucket(灵活分桶场景)
如果需要更灵活的时间范围分桶,可以用$bucket阶段,它会自动把文档分配到指定的时间区间桶里:
db.yourCollection.aggregate([ // 先获取集合中时间的最小/最大值,用来自动生成小时桶的边界 { $facet: { minMax: [ { $group: { _id: null, minDate: { $min: "$CreationDateTime" }, maxDate: { $max: "$CreationDateTime" } } } ], documents: [ { $sort: { CreationDateTime: 1 } } ] } }, { $unwind: "$minMax" }, { $bucket: { groupBy: "$documents.CreationDateTime", // 生成每个小时的时间边界 boundaries: { $map: { input: { $range: [ 0, { $dateDiff: { startDate: "$minMax.minDate", endDate: "$minMax.maxDate", unit: "hour" } }, 1 ] }, as: "hourOffset", in: { $dateAdd: { startDate: "$minMax.minDate", unit: "hour", amount: "$$hourOffset" } } } }, default: "other", // 处理超出最小/最大时间范围的文档 output: { firstDocument: { $first: "$documents" } } } } ])
注意点
- 如果你要的“首个文档”不是指该小时内最早创建的,而是集合中原始顺序的第一个,那可以去掉
$sort阶段,但这种场景比较少见。 - 替换代码里的
yourCollection为你实际的集合名称。
内容的提问来源于stack exchange,提问作者Cyrus the Great
相关产品推荐
相关产品推荐

