MongoDB 排序

MongoDB 排序(sort())完整指南

(MongoDB 8.0+,2025 年最新实践)

核心结论
sort() = 控制查询结果顺序必须配合索引才能高效
语法:.sort({ field1: 1, field2: -1 })1 升序,-1 降序


一、基本语法

db.collection.find()
  .sort({ field: 1 })    // 升序(ascending)
  .sort({ field: -1 })   // 降序(descending)
含义
1升序(从小到大)
-1降序(从大到小)

二、单字段排序示例

use company

// 按年龄升序
db.employees.find().sort({ age: 1 }).pretty()

// 按薪资降序
db.employees.find().sort({ salary: -1 }).limit(5).pretty()

// 按入职日期最新优先
db.employees.find().sort({ hireDate: -1 })

三、多字段排序(复合排序)

// 先按部门升序,再按薪资降序(同部门高薪优先)
db.employees.find()
  .sort({ 
    department: 1,    // 先排部门
    salary: -1        // 再排薪资
  })
  .pretty()
排序字段顺序
department: 1部门 A → Z
salary: -1薪资 高 → 低

执行顺序:从左到右,先排第一个字段,再排第二个。


四、与 limitskip 结合(分页)

// 第 2 页,每页 10 条,按创建时间倒序
db.posts.find()
  .sort({ createdAt: -1 })
  .skip(10)
  .limit(10)

必须先 sort()skip()/limit(),否则分页不稳定!


五、索引是排序性能之魂!

排序方式是否需要索引推荐索引
单字段{ age: 1 }
复合排序{ department: 1, salary: -1 }
无索引全表扫描,慢!
// 创建支持排序的索引
db.employees.createIndex({ department: 1, salary: -1 })

// 查看执行计划
db.employees.find()
  .sort({ department: 1, salary: -1 })
  .explain("executionStats")

索引使用规则(ESR 原则)
Equality → Sort → Range
即:等值匹配 → 排序字段 → 范围查询

// 最佳索引:支持过滤 + 排序
db.employees.createIndex({ 
  status: 1,        // E: 等值
  department: 1,    // S: 排序
  salary: -1        // S: 排序
})

六、特殊字段排序

1. 嵌套字段

// 按地址城市排序
db.users.find().sort({ "address.city": 1 })

// 索引
db.users.createIndex({ "address.city": 1 })

2. 数组字段(按数组中某个值)

// 按 scores 数组第一个元素排序
db.students.find().sort({ "scores.0": -1 })

// 按数组中最大值排序(需聚合)
db.students.aggregate([
  { $addFields: { maxScore: { $max: "$scores" } } },
  { $sort: { maxScore: -1 } }
])

3. 文本得分排序(全文搜索)

// 创建文本索引
db.articles.createIndex({ title: "text", content: "text" })

// 按相关度排序
db.articles.find(
  { $text: { $search: "MongoDB" } },
  { score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })

七、内存限制:排序超过 100MB 报错!

Error: error processing query: ... Sort exceeded memory limit of 104857600 bytes

解决方案

方案说明
创建索引让排序走索引,不占内存
允许磁盘排序.allowDiskUse(true)(仅聚合)
分批处理小批量排序
// 聚合中允许使用磁盘
db.logs.aggregate([
  { $sort: { timestamp: -1 } }
]).allowDiskUse(true)

八、生产级排序最佳实践

场景推荐方案
列表页sort + limit + 索引
分页skip 小数据,范围查询 大数据
排行榜sort + limit(100) + 索引
实时 feedssort({ ts: -1 }) + 索引
// 排行榜:前 100 名高薪员工
db.employees.find()
  .sort({ salary: -1 })
  .limit(100)
  .projection({ name: 1, salary: 1, _id: 0 })

九、GUI 工具排序

工具操作
MongoDB Compass查询栏 → Sort → 拖拽字段
MongoDB AtlasQuery → Sort: { age: 1 }
VS Code.sort({ field: -1 })

十、完整排序脚本示例

// sort_demo.js
use company

print("=== MongoDB 排序示例 ===\n")

// 1. 高薪前 5 名(降序)
print("1. 薪资最高前 5 人:")
db.employees.find()
  .sort({ salary: -1 })
  .limit(5)
  .projection({ name: 1, salary: 1, department: 1, _id: 0 })
  .forEach(printjson)

// 2. 按部门 + 薪资排序
print("\n2. 按部门升序、薪资降序:")
db.employees.find()
  .sort({ department: 1, salary: -1 })
  .limit(10)
  .projection({ name: 1, department: 1, salary: 1, _id: 0 })
  .forEach(printjson)

// 3. 最近入职的 3 人
print("\n3. 最近入职员工:")
db.employees.find()
  .sort({ hireDate: -1 })
  .limit(3)
  .projection({ name: 1, hireDate: 1, _id: 0 })
  .forEach(printjson)

// 4. 创建性能索引
print("\n创建复合索引:department + salary")
db.employees.createIndex({ department: 1, salary: -1 })
print("索引创建完成!")

运行:

mongosh sort_demo.js

十一、一句话总结

**“排序用 sort({ field: -1 }),性能靠 *索引*,分页弃 skip,用 **范围查询


快速排序模板

// 降序(最新)
.sort({ createdAt: -1 })

// 升序(最早)
.sort({ createdAt: 1 })

// 复合排序
.sort.sensor({ status: 1, priority: -1, createdAt: -1 })

// 高性能:确保有索引
db.collection.createIndex({ status: 1, priority: -1 })

官方文档

  • https://www.mongodb.com/docs/manual/reference/method/cursor.sort/
  • https://www.mongodb.com/docs/manual/indexes/

如需 动态排序字段多级排序聚合从 SQL ORDER BY 迁移实时排序流,欢迎继续提问!

文章已创建 2349

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部