$natural 是 MongoDB 中用于按文档物理插入顺序排序的特殊游标选项,仅支持在 find() 的 sort 参数或聚合管道的 $cursor 阶段中使用,不可直接用于 $sort 阶段;其行为受存储引擎、压缩、分片等影响,生产环境推荐用 _id 或时间字段索引替代以确保稳定性和性能。

聚合管道里不能直接写 $natural 作为 $sort 的值
因为 $natural 不是排序方向,而是特殊游标类型。你在 $sort 阶段写 {$natural: -1},MongoDB 会当成「按字段名 $natural 升序排」来解析——但文档里根本不存在这个字段,所以报错 FieldPath field names may not start with '$' 或类似提示。
常见错误写法:
db.collection.aggregate([
{ $sort: { $natural: -1 } }
])
这行代码语法上就非法:$sort 的键必须是真实字段名,不能是操作符前缀。
$natural 只能在 find() 游标选项或 $cursor 阶段里用
想按插入顺序倒序取最新文档,正确方式是避开 $sort,改用游标级控制:
- 在
find()中直接传{$natural: -1}作为 sort 参数(注意:这是find的特例,不是$sort) - 在聚合中,得把
$natural放进$cursor阶段(4.2+)或顶层cursor选项里
聚合中正确写法(v4.2+):
db.collection.aggregate([
{ $cursor: { sort: { $natural: -1 } } },
{ $match: { status: "active" } }
])
或者旧版聚合写法:
db.collection.aggregate([
{ $match: { status: "active" } }
], {
cursor: { sort: { $natural: -1 } }
})
为什么 $natural 排序在聚合里容易被忽略的兼容性问题
$natural 行为依赖存储引擎和数据写入模式:
- WiredTiger 下,
$natural: -1大致等价于按 _id 倒序(因 ObjectId 时间戳前置),但不严格保证——比如批量插入时内存缓冲可能打乱物理顺序 - 如果集合启用了 document-level compression 或 compact 操作后,
$natural顺序可能重排 - 分片集群中,
$natural只在单个 chunk 内有效,跨 shard 无全局自然序
所以生产环境用 $natural 做“最新 N 条”逻辑,必须搭配 _id 或时间字段二次校验,不能只信它。
替代方案:用 _id 或时间字段索引更稳
真正要取最新插入文档,优先建索引 + 显式排序:
-
db.collection.createIndex({ _id: -1 }),然后.sort({ _id: -1 }).limit(10) - 有明确时间字段(如
createdAt)就建{ createdAt: -1 }索引,再$sort - 两者都建复合索引(如
{ status: 1, createdAt: -1 }),配合$match提前过滤
这样既避免 $natural 的不确定性,又能让排序走索引、不触发内存限制报错 QueryExceededMemoryLimitNoDiskUseAllowed。


















