如何在MongoDB集合中按间隔提取指定位置的多个文档?
解决MongoDB提取每第10个文档的问题
你之前用$indexOfArray生成序号的方法逻辑错误,因为$$ROOT是单个文档对象,不是数组,$indexOfArray无法以此生成递增的行号。下面给你两种可行的解决方案:
方案一:使用$setWindowFields(MongoDB 5.0+推荐)
利用MongoDB 5.0新增的窗口函数$rowNumber可以直接生成全局递增的行号,效率更高:
db.your_collection_name.aggregate([ // 先按timestamp排序,确保文档顺序稳定(必须指定排序,否则行号无意义) { $sort: { timestamp: 1 } }, // 添加自增index字段 { $setWindowFields: { partitionBy: null, // 不分区,整个集合作为一个窗口 sortBy: { timestamp: 1 }, // 和排序阶段保持一致 output: { index: { $rowNumber: {} } // 生成从1开始的行号 } } }, // 筛选每第10个文档 { $match: { $expr: { $eq: [ { $mod: [ "$index", 10 ] }, 0 ] } } } ])
方案二:兼容旧版本MongoDB(低于5.0)
如果你的MongoDB版本不支持窗口函数,可以通过$group+$unwind的方式生成序号:
db.your_collection_name.aggregate([ { $sort: { timestamp: 1 } }, // 将所有文档存入一个数组 { $group: { _id: null, docs: { $push: "$$ROOT" } } }, // 展开数组并生成从0开始的索引 { $unwind: { path: "$docs", includeArrayIndex: "index" } }, // 因为索引从0开始,所以筛选第9、19...位(对应第10、20...个文档) { $match: { $expr: { $eq: [ { $mod: [ { $add: [ "$index", 1 ] }, 10 ] }, 0 ] } } }, // 恢复原文档结构 { $replaceRoot: { newRoot: "$docs" } } ])
注意事项
- 无论哪种方案,必须先执行排序,MongoDB集合本身没有固定的存储顺序,不排序的话生成的行号是随机的,筛选结果也无意义。
- 方案二在集合数据量很大时,
$group会把所有文档加载到内存,可能引发性能问题,优先推荐方案一。
内容的提问来源于stack exchange,提问作者repmsis
相关产品推荐
相关产品推荐

