字符串数值排序失败因默认字典序,需用collation配合同配置索引:建索引时显式指定{locale:"zh",numericOrdering:true},查询时collation参数必须完全一致,否则退化内存排序。

字符串字段按数值大小排序失败,不是因为写法错,而是 MongoDB 默认按字典序(ASCII)逐字符比对 —— "10" 会排在 "2" 前面。用 Collation 是最轻量、不改数据结构的解法,但必须注意它只在查询/聚合时生效,且依赖索引支持才能真正提速。
Collation 必须配合索引才有效
很多人加了 .collation({locale: "zh", numericOrdering: true}) 却发现排序还是乱的,根本原因是没建带 collation 的索引。MongoDB 不会自动为 collation 查询走默认索引。
- 建索引时必须显式带上相同 collation 配置,例如:
db.product.createIndex({ price: 1 }, { collation: { locale: "zh", numericOrdering: true } }) - 查询时 collation 参数必须和索引完全一致(包括 locale、numericOrdering、caseLevel 等),否则索引失效,退化为内存排序
- 同一个字段不能同时存在多个 collation 配置的索引,否则
createIndex会报错
中文拼音排序要设对 locale 和 strength
想让 "北京" 排在 "上海" 前面,仅靠 numericOrdering: true 不够 —— 它只管数字字符串,不管汉字顺序。中文拼音排序需组合两个关键项:
-
locale: "zh"或"zh-CN":触发拼音解析逻辑(注意不是"zh-Hans",部分驱动不识别) -
strength: 1或2:strength: 1按首字拼音排序,strength: 2区分声调(如“妈”和“麻”),生产环境通常用1即可 - 避免设
caseLevel: true,中文无大小写,开了反而干扰
完整示例:
db.users.find({ name: { $regex: "^张" } }).collation({ locale: "zh", strength: 1 }).sort({ name: 1 })
聚合管道里用 $sort 必须显式传 collation
聚合中 $sort 阶段不继承外层 collation,必须在 stage 内部指定,否则 collation 失效:
- 错误写法(collation 被忽略):
db.collection.aggregate([ { $sort: { price: 1 } } ]).collation({ locale: "zh", numericOrdering: true }) - 正确写法(collation 写进 $sort):
db.collection.aggregate([ { $sort: { price: 1, _id: 1 } }, { $collation: { locale: "zh", numericOrdering: true } } ])注意:MongoDB 5.0+ 支持$collation阶段;旧版本只能把 collation 放在aggregate()方法调用时传参 - 如果排序字段含空值或缺失,collation 下可能被归到一起,建议加
$match过滤掉再排
collation 是声明式方案,不改变原始数据,但它的行为高度依赖索引定义和驱动版本兼容性。最容易被忽略的是:开发环境用了 collation 查询,测试通过,上线后因索引缺失或 locale 字符串拼错,直接退化成字典序 —— 所以每次上线前务必用 explain() 确认是否命中带 collation 的索引。


















