C#操作MongoDB查询避免正则 用Collation实现大小写不敏感匹配
你当前代码触发正则匹配的核心原因是:MongoDB C# 驱动无法将LINQ表达式中的ToLower()方法翻译成数据库原生的字符串比较逻辑,会默认降级生成正则表达式查询,这类查询无法命中普通索引,性能较差。
方案一:使用Collation(排序规则)实现无正则的大小写不敏感查询
Collation是MongoDB 3.4+版本原生支持的字符串比较规则,可直接在比较层面实现大小写不敏感匹配,完全不会生成正则。
注意:使用时必须去掉LINQ表达式中所有的ToLower()调用,否则驱动依然会生成正则逻辑。
如果你的GetItemsByQuery方法支持传入查询配置,可按如下方式修改:
// 构造查询条件时直接比较原始值,不需要手动转小写 var query = Query<Table1> .Where(p => p.Field1 == string1) // 追加Collation配置:strength=Secondary表示比较时不区分大小写、不区分重音符号 .WithOptions(new QueryOptions { Collation = new Collation("zh", strength: CollationStrength.Secondary) }); var result = GetItemsByQuery(query);
如果GetItemsByQuery是基于MongoDB驱动原生的Find接口封装,也可以直接在Find层面指定Collation:
var filter = Builders<Table1>.Filter.Eq(p => p.Field1, string1); var findOptions = new FindOptions { Collation = new Collation("zh", strength: CollationStrength.Secondary) }; var result = _mongoCollection.Find(filter, findOptions).ToList();
方案二:其他不触发正则的实现方式
- 冗余小写字段方案
在Table1实体中新增Field1Lower字段,写入数据时提前将Field1转为小写存入该字段,查询时直接匹配转成小写的目标字符串即可。
该方案兼容所有MongoDB版本,配合// 数据写入时维护冗余字段 var doc = new Table1 { Field1 = "DemoData", Field1Lower = "DemoData".ToLowerInvariant() }; // 查询时直接匹配冗余字段,完全走普通等值查询逻辑 var targetLower = string1.ToLowerInvariant(); var result = GetItemsByQuery(Query<Table1>.Where(p => p.Field1Lower == targetLower));Field1Lower字段上的普通索引可达到最优查询性能,缺点是需要额外占用少量存储空间,写入时需要维护冗余字段的一致性。 - 预创建带Collation的索引
如果不想每次查询都手动指定Collation,可以直接在Field1字段上创建绑定大小写不敏感Collation的索引,后续查询只要指定和索引完全一致的Collation配置,就会自动命中索引,不会生成正则:var indexKey = Builders<Table1>.IndexKeys.Ascending(p => p.Field1); var indexOpt = new CreateIndexOptions { Collation = new Collation("zh", strength: CollationStrength.Secondary), Name = "idx_field1_case_insensitive" }; _mongoCollection.Indexes.CreateOne(new CreateIndexModel<Table1>(indexKey, indexOpt));
注意:不要在LINQ中使用
p.Field1.Equals(string1, StringComparison.OrdinalIgnoreCase)这类写法,C#驱动无法将该重载翻译为原生查询,依然会生成正则匹配逻辑,和ToLower()写法存在一样的性能问题。
内容的提问来源于stack exchange,提问作者NewCSharp
相关产品推荐
相关产品推荐

