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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:12:54