$documents 并非 mongodb 7.0 新增阶段,自 3.2 已存在;其在 7.0 中看似变快,实因新 slot-based 执行引擎支持零拷贝传递内存数组,绕过旧引擎序列化/反序列化开销,适用于单元测试构造输入,不可替代真实集合查询。

$documents 不是 MongoDB 7.0 引入的新阶段,它在 3.2 就已存在;所谓“7.0 中更高效”其实是误传——真正带来性能跃升的是底层执行引擎变更,$documents 只是恰好能更好适配新机制的少数几个阶段之一。
为什么有人觉得 $documents 在 7.0 里变快了
根本原因不是 $documents 本身被优化,而是它天然绕过了 Slot-Based 执行引擎的兼容性回退路径:
- 旧引擎处理
$documents需先序列化输入数组为 BSON 文档流,再逐个反序列化;新引擎直接把数组元素作为 slot 值传递,零拷贝 -
$documents输入是内存内数组(如[{a:1},{a:2}]),不涉及磁盘 I/O 或集合扫描,完全规避了旧引擎中“中间结果反复打包/解包”的开销 - 当它用在
$facet或子管道中构造测试数据时,整个流程不触发索引查找、分片路由或聚合拆分逻辑,执行路径极短
$documents 的典型使用场景和陷阱
它只适用于“从内存数组构造文档流”,不是替代集合查询的通用方案。常见误用包括把它塞进生产聚合管道开头去“模拟数据源”——这反而会破坏索引下推和阶段重排。
- ✅ 正确:单元测试中快速构造输入,验证
$group或$project行为db.collection.aggregate([ {$documents: [{x:1,y:2}, {x:3,y:4}] }, {$group: {_id: null, sumX: {$sum: "$x"}}} ]) - ❌ 错误:试图用
{$documents: {$map: {...}}}动态生成大量文档——内存爆涨且无法利用索引 - ⚠️ 注意:
$documents不支持变量引用(如$$ROOT)、不参与 explain 的 stageStats 统计,explain("executionStats")中它不显示 executionTimeMillis
对比 $documents 和真实集合读取的性能差异
在 7.0 中,对一个有百万文档的集合执行 $match + $limit,耗时主要花在磁盘读取和 BSON 解析上;而 $documents 的“快”只是因为跳过了这些环节。两者解决的问题完全不同:
- 真实查询瓶颈在 I/O 和索引效率,优化重点是复合索引设计、
$match前置、allowDiskUse控制 -
$documents的瓶颈只在内存带宽,只要数组不大于几十 MB,基本无感知;但它无法替代任何需要持久化存储或事务语义的场景 - 若强行用
$documents加载全量集合数据(比如db.coll.find().toArray()后传入),反而比原生聚合慢——Node.js 驱动里 BSON 序列化开销远高于 mongod 内部 slot 传递
真正影响 7.0 聚合性能的是你是否让 $match 命中索引、是否避免 $unwind 后爆炸式膨胀、以及分片环境下是否含 foreignCollection 的 $lookup ——$documents 只是个安静的工具,别给它加戏。











