在MongoDB的实际运维中,错误码1910往往出现在涉及排序规则(collation)的操作里。当数据库发现本次操作要求的collation与已有对象(如集合或索引)的collation不兼容时,就会拒绝执行并返回1910。理解这个错误的本质,要先弄清楚collation在MongoDB里到底控制了什么:它决定了字符串比较时的语言规则、是否区分大小写、是否忽略变音符号等。如果同一查询路径上不同环节使用了互相矛盾的collation,引擎无法保证结果顺序的一致性,于是触发冲突。

1910错误的触发场景与底层原理
MongoDB从3.4版本开始引入collation特性,每一个集合在创建时可以指定一个默认collation,每一个索引也可以绑定自己的collation,而单次查询或聚合也能临时传入collation参数。问题在于,当查询使用了某个索引,但查询自身的collation与索引的collation不一致,并且索引本身是有序索引(如普通升序索引或文本索引的排序依赖)时,MongoDB为了保证排序正确性,会要求二者必须兼容。若集合默认collation、索引collation、操作collation三者出现不可兼容的组合,就会抛出1910。
具体来说,collation由locale、strength、caseLevel、caseFirst等字段构成。其中strength=1表示仅基础字符比较(忽略大小写与变音),strength=3表示区分大小写与变音。如果一个索引以strength=1建立,而查询以strength=3执行,MongoDB无法用该索引直接返回符合查询排序语义的结果,又不允许在冲突下强行使用,于是报1910。这并非数据损坏,而是引擎的一种保护机制。
从源码层面看,查询规划器在枚举索引时,会调用collation的兼容检查方法。若发现操作collation与候选索引collation的locale不同,或strength等级导致比较语义变化,就标记该索引不可用并向上返回冲突错误。因此1910常出现在迁移旧集合、混用默认collation与显式collation、以及多语言站点切换locale的场合。
创建索引与查询时如何统一Collation
避免1910最直接的方式,是在创建索引和发起查询时显式声明一致的collation。假设我们的集合存储多语言用户名,希望不区分大小写排序,可以在建索引时指定collation,随后查询也使用同样的collation。下面示例在Python驱动中演示正确做法:
from pymongo import MongoClient, ASCENDING
client = MongoClient('127.0.0.1', 27017)
db = client['test_db']
users = db['users']
# 创建索引时绑定collation,locale为中文,strength=2表示忽略大小写
users.create_index(
[('name', ASCENDING)],
name='name_idx',
collation={'locale': 'zh', 'strength': 2}
)
# 查询时传入相同的collation,避免1910
cursor = users.find(
{'name': {'$regex': '^张'}},
collation={'locale': 'zh', 'strength': 2}
)
for doc in cursor:
print(doc)
上述代码中,索引与查询都使用{'locale': 'zh', 'strength': 2},MongoDB能够安全复用索引完成排序与过滤。反之,如果查询不传collation,而集合默认collation是simple(二进制比较),同样可能与索引冲突。因此推荐将核心查询路径上的collation写成常量,统一引用。
在聚合管道里,也需要在最外层或具体stage中声明collation。例如$sort阶段若依赖带collation的索引,必须在aggregate调用时传入collation参数。很多开发者误以为在$match里写正则就能自动继承索引collation,实际上聚合操作的collation是独立指定的,遗漏就会导致1910或性能退化。
已有集合的Collation变更与避坑策略
对于已经存在数据的集合,MongoDB不允许直接修改集合级别的默认collation。如果早期建集合时用了simple,现在要改成zh且业务要求索引兼容,只能新建集合并指定目标collation,再将数据迁移过去,最后重建所有相关索引。这个过程要评估停机窗口,因为大集合的导出导入可能耗时较长。
另一个常见误区是认为删除索引再重建就能解决1910。其实如果集合默认collation没变,新建索引不指定collation就会继承集合的默认规则;此时查询若带了不同collation,依旧冲突。正确做法是:要么查询不传collation以使用集合默认,要么索引和查询都显式传相同collation。可以通过db.runCommand({listIndexes: 'users'})查看每个索引绑定的collation字段,确认是否一致。
在分片集群中,1910还可能因各分片集合collation不一致而出现。运维脚本批量建集合时,若未显式指定collation,不同版本MongoDB或不同配置模板可能生成不同的默认项。因此建议在集群初始化模板里固定collation参数,并在CI流程中用脚本校验索引与集合的collation兼容性,将1910消灭在发布之前。