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

如何从MongoDB每10秒一条的集合中按1小时间隔提取单条记录

MongoDB按小时间隔提取单条记录方案

一、现有普通集合的聚合实现

1. 精确匹配指定分秒的记录

如果需要严格保留每个小时中08分20秒的记录(如示例中的2021-11-26T15:08:20.000+00:00),可以通过以下聚合管道实现:

db.collection1.aggregate([
  // 筛选分钟=8、秒=20的记录
  {
    $match: {
      $expr: {
        $and: [
          { $eq: [{ $minute: "$datetime" }, 8] },
          { $eq: [{ $second: "$datetime" }, 20] }
        ]
      }
    }
  },
  // 按年-月-日-小时分组,确保每个小时仅保留一条记录(避免毫秒级重复)
  {
    $group: {
      _id: {
        year: { $year: "$datetime" },
        month: { $month: "$datetime" },
        day: { $dayOfMonth: "$datetime" },
        hour: { $hour: "$datetime" }
      },
      record: { $first: "$$ROOT" }
    }
  },
  // 还原完整记录结构
  {
    $replaceRoot: { newRoot: "$record" }
  },
  // 按时间升序排序
  {
    $sort: { datetime: 1 }
  }
])

2. 提取每小时最接近指定分秒的记录

如果部分小时没有刚好08:20的记录,可改为提取该小时内与目标时间最接近的记录:

db.collection1.aggregate([
  // 计算每条记录对应小时的目标时间(08:20),并计算时间差绝对值
  {
    $addFields: {
      targetDatetime: {
        $dateFromParts: {
          year: { $year: "$datetime" },
          month: { $month: "$datetime" },
          day: { $dayOfMonth: "$datetime" },
          hour: { $hour: "$datetime" },
          minute: 8,
          second: 20,
          timezone: "UTC" // 根据业务时区调整
        }
      },
      timeDiff: { $abs: { $subtract: ["$datetime", "$targetDatetime"] } }
    }
  },
  // 按小时分组,找出每组内的最小时间差及对应记录
  {
    $group: {
      _id: {
        year: { $year: "$datetime" },
        month: { $month: "$datetime" },
        day: { $dayOfMonth: "$datetime" },
        hour: { $hour: "$datetime" }
      },
      closestRecord: { $first: "$$ROOT" },
      minDiff: { $min: "$timeDiff" }
    }
  },
  // 过滤出时间差等于最小差的记录
  {
    $match: {
      $expr: { $eq: ["$closestRecord.timeDiff", "$minDiff"] }
    }
  },
  // 移除临时字段,还原记录结构
  {
    $replaceRoot: {
      newRoot: {
        $mergeObjects: [
          "$closestRecord",
          { targetDatetime: "$$REMOVE", timeDiff: "$$REMOVE" }
        ]
      }
    }
  },
  { $sort: { datetime: 1 } }
])

二、转为时间序列集合后的优化方案

时间序列集合针对时间型数据做了存储和查询优化,转换步骤如下:

// 将普通集合转为时间序列集合(datetime为时间字段)
db.collection1.aggregate([
  { $out: { db: "your_database", coll: "collection1_ts", timeseries: { timeField: "datetime" } } }
])

转换后,按小时提取记录的聚合操作性能会显著提升,示例如下:

db.collection1_ts.aggregate([
  // 按小时截断时间作为分组键,取每组第一条记录
  {
    $group: {
      _id: { $dateTrunc: { date: "$datetime", unit: "hour", timezone: "UTC" } },
      record: { $first: "$$ROOT" }
    }
  },
  { $replaceRoot: { newRoot: "$record" } },
  { $sort: { datetime: 1 } }
])

如果仍需保留指定分秒的记录,直接复用普通集合的$match逻辑即可,时间序列集合会自动利用时间索引加速查询。

内容的提问来源于stack exchange,提问作者Aislan Diego

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 16:43:14