是什么
collation(排序规则)定义字符串怎么比较:是否区分大小写、是否区分变音符号、数字按字符还是按数值比较、中文按拼音还是笔画排序。默认情况下 MongoDB 按二进制比较字符串,大写字母永远排在小写字母前面。索引与查询必须使用一致的 collation 才能互相命中,这是 collation 最容易踩的坑。
基本信息
| 创建索引 | createIndex({ name: 1 }, { collation: { locale: "zh", strength: 2 } }) |
|---|---|
| strength | 1 忽略大小写与变音;2 区分变音但不区分大小写;3 默认,区分大小写与变音;4 再考虑标点层级;5 完全相同 |
| 查询 | find(...).collation({ locale: "zh", strength: 2 }) |
| 聚合 | db.coll.aggregate(pipeline, { collation: { locale: "zh" } }) |
| 集合默认 | createCollection 时指定 collation,之后索引与查询可继承 |
| 常用选项 | numericOrdering(数字按数值比较)、caseFirst、normalization、backwards |
典型使用场景
- 不区分大小写的登录名查询:邮箱、用户名按忽略大小写的规则比较,避免存两套
- 中文排序:按拼音序排出通讯录、地区列表,比按二进制排更符合使用习惯
- 忽略变音符号检索:拉丁字母带音标的数据按基础字母匹配
- 数字字符串排序:编号列按数值大小排序,避免出现 10 排在 9 前面
- 迁移对照:把历史数据的比较规则与业务预期核对,找出因规则不一致造成的重复数据
创建与查询
创建与查询
db.users.createIndex({ name: 1 }, { collation: { locale: "zh", strength: 2 } }) # 索引按拼音、忽略大小写
db.users.find({ name: "张伟" }).collation({ locale: "zh", strength: 2 }) # 查询必须带同样规则
db.users.find({ name: "zhang" }).collation({ locale: "en", strength: 1 }) # 忽略大小写与变音
db.orders.aggregate([ # 聚合里也要显式指定
{ $sort: { code: 1 } }
], { collation: { locale: "en", numericOrdering: true } }) # 编号按数值排序
db.users.getIndexes() # 确认索引上的 collation
db.users.dropIndex("name_1") # collation 不能改,只能删了重建strength 取值读法
| strength | 比较规则 | 典型效果 |
|---|---|---|
| 1 | 主级:只比基础字符 | a 与 A、é 与 e 视为相同 |
| 2 | 次级:加变音符号 | 区分 é 与 e,仍不区分大小写 |
| 3 | 三级(默认) | 区分大小写与变音 |
| 4 | 四级 | 再考虑标点等层级差异 |
| 5 | 完全相同 | 等价于按二进制比较 |
索引带 collation 而查询不带时,查询会按二进制比较,索引无法被使用,性能退化且结果可能少匹配;反过来查询带 collation 而索引不带也一样用不上,两边必须完全一致。
collation 只能在创建索引时指定,之后无法修改,需要改规则必须删索引重建。如果整库的比较规则统一,直接用集合默认 collation 更省心;中文排序的具体可用变体(拼音、笔画等)以所用版本的 ICU 支持为准。