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

如何在MongoDB已排序聚合结果中抽取大集合的每第N条记录

解决方案

前置准备

首先为集合创建复合索引,保证筛选和排序阶段都可以命中索引,避免内存排序带来的性能损耗:

db.yourCollectionName.createIndex({ searches: 1, hour: -1 })

推荐方案(MongoDB 5.0+,支持百万级数据高效执行)

使用MongoDB 5.0引入的$setWindowFields窗口函数实现排序编号,性能远高于传统的分页或全量分组方案:

const N = 20000; // 间隔抽取的条数
db.yourCollectionName.aggregate([
  // 筛选符合条件的记录
  {
    $match: {
      searches: {
        $in: [ObjectId('614965487d5d1c55794ce670')],
      },
    },
  },
  // 按hour降序排序
  { $sort: { hour: -1 } },
  // 按排序顺序为每条记录生成连续编号
  {
    $setWindowFields: {
      sortBy: { hour: -1 },
      output: {
        docRank: {
          $documentNumber: {}
        }
      }
    }
  },
  // 过滤出第1条、每第N条记录
  {
    $match: {
      $expr: {
        $or: [
          { $eq: [ { $mod: [ "$docRank", N ] }, 0 ] },
          { $eq: [ "$docRank", 1 ] }
        ]
      }
    }
  },
  // 仅保留hour字段
  { $project: { _id: 0, hour: 1 } }
])

最后一条记录补充

上述查询会返回第1、20000、40000...条的hour值,如果需要包含排序后的最后一条记录,可以在拿到结果后,单独执行以下查询获取最小hour(降序排序的最后一条对应hour最小),手动加入结果集即可:

db.yourCollectionName.find({
  searches: { $in: [ObjectId('614965487d5d1c55794ce670')] }
}).sort({ hour: 1 }).limit(1).hint({ searches: 1, hour: -1 })

兼容方案(MongoDB 5.0以下版本)

如果你的MongoDB版本不支持窗口函数,可以使用全量分组后按索引取值的方案,适合符合筛选条件的记录数在百万以内的场景:

const N = 20000;
db.yourCollectionName.aggregate([
  { $match: { searches: { $in: [ObjectId('614965487d5d1c55794ce670')] } } },
  { $sort: { hour: -1 } },
  // 将所有符合条件的hour存入数组
  { $group: { _id: null, hours: { $push: "$hour" } } },
  // 按间隔N取值
  {
    $project: {
      _id: 0,
      sampleHours: {
        $reduce: {
          input: { $range: [0, { $size: "$hours" }, N] },
          initialValue: [],
          in: { $concatArrays: ["$$value", [{ $arrayElemAt: ["$hours", "$$this"] }]] }
        }
      }
    }
  }
])

该方案的缺点是单条BSON有16MB上限,如果符合条件的记录数过多会触发查询报错,优先使用窗口函数方案。

内容的提问来源于stack exchange,提问作者Martin Ratinaud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 13:09:03