sort() 是 mongodb 控制查询结果顺序的唯一方式,只影响游标遍历顺序;方向参数必须为 1 或 -1,多字段排序需显式指定各字段方向,复合排序需匹配索引字段顺序与方向,数组排序按极值比较,java 驱动应使用 sorts 工具类,未命中索引将触发内存排序导致性能问题。

sort() 方法是 MongoDB 中控制查询结果顺序的唯一标准方式,直接决定返回文档的排列逻辑。它不改变数据本身,只影响游标遍历顺序。
sort() 语法与方向参数必须成对出现
方向只能是 1(升序)或 -1(降序),不能省略、不能用 true/false 或字符串 "asc" 替代:
- 错误写法:db.users.find().sort({age: "asc"})、db.users.find().sort({age: true})
- 正确写法:db.users.find().sort({age: 1})(升序)、db.users.find().sort({age: -1})(降序)
- 多字段排序时,每个字段都必须显式指定方向:db.users.find().sort({status: 1, created_at: -1}),先按 status 升序,再在相同 status 内按 created_at 降序
复合排序必须匹配索引字段顺序和方向
如果希望排序走索引避免内存排序(cursor.explain() 中出现 executionStages.stage === "SORT" 就说明没走索引),索引定义必须满足:
- 字段顺序与 sort() 参数一致
- 每个字段的方向要么完全相同,要么全为 1(因为升序索引可反向扫描支持 -1,但降序索引不能正向支持 1)
- 示例:db.users.createIndex({status: 1, created_at: -1}) 可以支撑 sort({status: 1, created_at: -1}),但不支撑 sort({status: 1, created_at: 1})(第二个字段方向冲突)
- 若只建了 {status: 1} 单字段索引,则仅能加速单字段 sort({status: 1}) 或 sort({status: -1}),多字段排序仍会触发内存排序
数组字段排序行为容易被误解
MongoDB 对数组字段排序时,并不展开数组,而是按 BSON 类型规则取极值比较:
- 升序时,拿数组中「最小元素」参与比较(如 [5, 1, 3] 视为 1)
- 降序时,拿数组中「最大元素」参与比较(如 [5, 1, 3] 视为 5)
- 空数组 [] 被视为比 null 还小,排在最前(升序)或最后(降序)
- 如果真要按数组长度或特定位置排序,得用 $arrayElemAt 或 $size 在聚合管道里预处理,sort() 本身做不到
Java 驱动里别漏掉 Sorts 工具类
Java 客户端不用手拼 BSON 文档,应使用 Sorts 工具类生成排序对象:
- 升序:Sorts.ascending("name")
- 降序:Sorts.descending("score")
- 多字段:Sorts.orderBy(Sorts.ascending("type"), Sorts.descending("updated"))
- 直接传 new Document("name", 1) 虽然能跑通,但失去类型安全和 IDE 提示,且无法链式组合其他排序条件
真正卡顿的点往往不在语法写错,而在没意识到排序是否命中索引 —— 特别是当集合变大后,sort() 没走索引就会触发内存排序,一旦结果集超过 100MB(默认 maxSortMemoryUsageBytes),查询直接失败。务必用 explain("executionStats") 看 totalDocsExamined 和是否有 SORT 阶段。











