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

Node.js Mongoose如何按固定间隔查询MongoDB文档子集?

嘿,这个需求完全可以实现,我给你分享两种靠谱的方案,分别适合不同的MongoDB版本和性能需求:

方案一:用聚合管道高效筛选(推荐MongoDB 5.0+)

如果你的MongoDB版本在5.0及以上,$setWindowFields是最优解——它能给每个文档生成连续的行号,然后我们只需要筛选符合你要求的行号即可,性能比循环skip好太多。

步骤很清晰:

  1. 先给文档排序(必须!不然「第N个文档」的顺序是不确定的,这里用_id排序,对应默认的插入顺序);
  2. 用$setWindowFields给每个文档添加行号;
  3. 筛选行号为1,或者行号是300的倍数的文档(对应你要的第1、300、600...个文档);
  4. 可选:移除行号字段,只保留原文档内容。

代码示例:

const targetDocs = await YourModel.aggregate([
  // 按插入顺序排序(如果需要其他顺序,改这里的sort条件即可)
  { $sort: { _id: 1 } },
  // 生成从1开始的连续行号
  {
    $setWindowFields: {
      partitionBy: null, // 整个集合作为一个分区
      sortBy: { _id: 1 },
      output: {
        rowNumber: { $rowNumber: {} }
      }
    }
  },
  // 筛选符合条件的行号:第1个,或者300的倍数
  {
    $match: {
      $or: [
        { rowNumber: 1 },
        { $expr: { $eq: [{ $mod: ["$rowNumber", 300] }, 0] } }
      ]
    }
  },
  // 移除行号字段,返回原文档结构
  { $unset: "rowNumber" }
]);

方案二:循环Skip+Limit(兼容低版本,但性能一般)

如果你的MongoDB版本低于5.0,只能用传统的skip+limit循环来实现。不过要注意:当skip的数值很大时,MongoDB需要扫描前面所有的文档,性能会明显下降,所以这个方案适合数据量不是特别大的场景,或者你能接受稍慢的查询速度。

代码示例:

const batchStep = 300;
const results = [];

// 先取第一个文档
const firstDoc = await YourModel.findOne().sort({ _id: 1 });
if (firstDoc) {
  results.push(firstDoc);
}

// 从第300个开始,每隔300个取一个(注意skip是从0计数的,第300个的索引是299)
let currentSkip = batchStep - 1;
while (true) {
  const doc = await YourModel.findOne()
    .sort({ _id: 1 })
    .skip(currentSkip)
    .limit(1);
  
  if (!doc) break; // 没有更多文档时退出循环
  results.push(doc);
  currentSkip += batchStep;
}

重要提醒

  • 一定要指定排序条件:如果不排序,MongoDB返回的文档顺序是不稳定的,你取到的「第N个文档」可能每次都不一样。优先用有索引的字段排序(比如_id默认有索引),能大幅提升查询速度。
  • 聚合方案的性能远优于循环Skip:对于10万+文档的场景,强烈推荐用方案一,循环Skip在后期会有明显的性能瓶颈。

内容的提问来源于stack exchange,提问作者Hữu Linh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:40:07