mongodb默认字符串比较区分大小写(binary collation),但真正实现语种敏感的精确区分需显式设置collation并指定strength≥3,且查询、索引、驱动版本必须三者对齐,否则无法生效或退化为全表扫描。

MongoDB 默认的字符串比较是区分大小写的,但仅限于字节层面(binary collation),不支持语言敏感的大小写处理;真要实现“按英语/中文等语种规则区分大小写的精确查询”,必须显式设置 collation,否则 find({name: "Alice"}) 可能意外匹配到 "alice" 或根本查不到——取决于你用的是默认 binary 还是已有 locale collation。
为什么加 collation 才算“真正区分大小写”?
MongoDB 的默认排序规则(collation: {locale: "en", strength: 2})会忽略大小写(strength=2 表示只比较 base 字符,忽略 case 和 accents)。想让 "A" ≠ "a",必须把 strength 提升到 3 或更高:
-
strength: 1:只比字母是否相同(忽略大小写、重音、变音) -
strength: 2:比字母 + 重音(仍忽略大小写) -
strength: 3:比字母 + 重音 + 大小写 → ✅ 真正区分大小写 -
strength: 4:再加标点/空格差异(极少用)
注意:collation 必须和索引定义一致,否则查询无法使用索引 —— 比如你建了带 {locale:"en", strength:3} 的索引,但查询没带 collation,MongoDB 就不会走这个索引。
如何在 find() 中正确传入 collation
不是所有驱动都支持在查询里直接写 collation,Node.js(v4.15+)、Python(pymongo 3.7+)、Java(driver 3.12+)可以,但必须放在查询选项对象里,不能塞进 filter:
db.users.find(
{ name: "Admin" },
{ collation: { locale: "en", strength: 3 } }
)
常见错误:
- 写成
db.users.find({ name: "Admin", collation: {...} })→collation被当成了 filter 字段,无效 - 用
findOneAndUpdate时漏掉collation选项 → 更新可能命中错误文档 - 在聚合管道中用
$match,却没在 stage 外层加collation→ 不生效(需在aggregate([...], {collation: ...})里传)
索引必须显式声明 collation 才能加速大小写敏感查询
即使查询带了 collation,若字段上没有对应规则的索引,MongoDB 会退化为全表扫描。建索引时必须镜像查询所用的 collation:
db.users.createIndex(
{ name: 1 },
{ collation: { locale: "en", strength: 3 } }
)
关键限制:
- 同一个字段不能同时存在多个不同
collation的索引(会报错) - 如果业务既要大小写敏感查,又要不敏感查,得建两个索引:
{name:1, collation:{strength:3}}和{name:1, collation:{strength:2}} - 中文场景慎用
locale: "zh":多数 MongoDB 版本对中文 collation 支持有限,strength:3下仍可能把“张”和“張”视为相同(繁简未标准化),建议优先用locale: "simple"+strength:3做字节级严格匹配
collation 不是开关,是契约:查询、索引、甚至集合默认 collation(createCollection(..., {collation:...}))三者必须对齐,否则行为不可预测。最易被忽略的是——驱动版本太旧不支持该选项,或用了 mongosh 但没确认当前 shell 版本是否 ≥1.8(早期版本 collation 支持不完整)。











