【问题标题】:MongoDB and C#: Case insensitive searchMongoDB 和 C#:不区分大小写的搜索
【发布时间】:2010-12-16 08:56:31
【问题描述】:

我正在使用MongoDBC# driver for MongoDB

我最近发现 MongoDB 中的所有查询都区分大小写。如何进行不区分大小写的搜索?

我找到了一种方法:

Query.Matches(
    "FirstName", 
    BsonRegularExpression.Create(new Regex(searchKey,RegexOptions.IgnoreCase)));

【问题讨论】:

    标签: c# .net mongodb mongodb-.net-driver case-insensitive


    【解决方案1】:

    最简单、最安全的方法是使用Linq

    var names = namesCollection.AsQueryable().Where(name =>
        name.FirstName.ToLower().Contains("hamster"));
    

    正如tutorialToLowerToLowerInvariantToUpperToUpperInvariant 中所解释的,它们都以不区分大小写的方式执行匹配。之后,您可以使用所有受支持的字符串方法,例如 ContainsStartsWith

    这个例子会生成:

    {
        "FirstName" : /hamster/is
    }
    

    i 选项使其不区分大小写。

    【讨论】:

    • 这应该是最佳答案!
    • 怎么知道query使用Linq有没有找到东西,我只是试了一下,不知道是否满足我的条件
    • @Kyojimaru 过滤器在哪里。它只返回通过过滤器并满足条件的内容。如果您想自己获取项目,请使用foreach 循环。如果您只想知道是否有任何文档满足条件,可以使用 Any 扩展方法。
    • @Kyojimaru 那么您没有任何满足该条件的文件
    • 有一个非常重要的细节我花了好几个小时才弄清楚:使用 Linq 时不能使用 ToLower 和 Equals,而必须使用“==”。即: .Where(x => x.Name.ToLower().Equals("fernando")) 抛出异常,而 .Where(x => x.Name.ToLower() == "fernando") 工作得很好!
    【解决方案2】:

    我刚刚实现了这个比任何其他建议都简单得多。但是我意识到,由于这个问题的年代久远,这个功能当时可能还不可用。

    使用 Bson 正则表达式构造函数的选项来传递不区分大小写的情况。我刚刚查看了源代码,发现'i'就是你所需要的。例如。

    var regexFilter = Regex.Escape(filter);
    var bsonRegex = new BsonRegularExpression(regexFilter, "i");
    
    Query.Matches("MyField", bsonRegex);
    

    您不必为搜索保留两次记录。

    【讨论】:

    • 警告:如果传入的过滤器字符串包含正则表达式符号,这将失败。例如,如果您传入一个电子邮件地址“john+smith@gmail.com”,由于“+”符号,它将返回 0 条记录。
    • 如果有人可以推荐解决@Justin 所做评论的方法,我很乐意更新此答案。我目前没有使用 MongoDb,因此无法进行调查。
    • @bassbytesbikes 你最好的办法是用Regex.Escape(filter) 转义filter 中的字符,然后传递它。
    • 不应该吗? var bsonRegex = new BsonRegularExpression(regexFilter, "i");
    【解决方案3】:

    尝试使用这样的东西:

    Query.Matches("FieldName", BsonRegularExpression.Create(new Regex(searchKey, RegexOptions.IgnoreCase)))
    

    【讨论】:

    • 没问题,但要小心为该字段创建索引。
    • 使用 /^FirstName"$/i,上面的查询将匹配 "WhateverFirstName"
    【解决方案4】:

    您可能需要存储该字段两次,一次是使用其实际值,另一次是全部小写。然后,您可以查询小写版本以进行不区分大小写的搜索(不要忘记将查询字符串也小写)。

    这种方法适用于(或者是必要的)许多数据库系统,并且它应该比基于正则表达式的技术表现更好(至少对于前缀或精确匹配)。

    【讨论】:

    • 这不是 IMO 的实际解决方案。正确答案在这里。 stackoverflow.com/a/8246621/309644
    • @afollestad 取决于。使用全文搜索有其自身的缺点。常规的 B-Tree 索引字段可以做一些不错的事情,例如前缀搜索,或者更容易与其他字段组合。
    【解决方案5】:

    正如 i3arnon 回答的那样,您可以使用 Queryable 进行不区分大小写的比较/搜索。我发现,我不能使用 string.Equals() 方法,因为它不受支持。如果您需要进行比较,很遗憾 Contains() 将不合适,这让我在很长一段时间内一直在努力寻找解决方案。

    对于任何想要进行字符串比较的人,只需使用 == 而不是 .Equals()。

    代码:

    var names = namesCollection.AsQueryable().Where(name =>
        name.FirstName.ToLower() == name.ToLower());
    

    【讨论】:

    • 非常感谢您的回答。我尝试遵循 i3arnon 的回答并一直遇到错误 {document}{key}.ToLower() is not supported。原来如你所说:不支持Equals。
    • .AsQueryable() 始终将您的查询转换为聚合管道,比基本查询更慢
    【解决方案6】:

    您还可以使用 MongoDB 的内置过滤器。它可能会更容易使用一些 mongo 的方法。

    var filter = Builders<Model>.Filter.Where(p => p.PropertyName.ToLower().Contains(s.ToLower()));
    var list = collection.Find(filter).Sort(mySort).ToList();
    

    【讨论】:

      【解决方案7】:

      对于 MongoDB 3.4+,推荐的方法是使用索引。 见https://jira.mongodb.org/browse/DOCS-11105?focusedCommentId=1859745&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-1859745

      我正在通过不区分大小写的方式成功搜索: 1. 使用排序规则为语言环境(例如:“en”)创建索引,强度为 1 或 2。有关详细信息,请参阅 https://docs.mongodb.com/manual/core/index-case-insensitive/

      1. 在对 MongoDb 集合执行搜索时使用相同的排序规则。

      举个例子:

      为不区分大小写创建强度为 1 或 2 的排序规则

      private readonly Collation _caseInsensitiveCollation = new Collation("en", strength: CollationStrength.Primary);
      

      创建索引。就我而言,我索引了几个字段:

      private void CreateIndex()
      {
          var indexOptions = new CreateIndexOptions {Collation = _caseInsensitiveCollation};
          var indexDefinition
              = Builders<MyDto>.IndexKeys.Combine(
                  Builders<MyDto>.IndexKeys.Ascending(x => x.Foo),
                  Builders<MyDto>.IndexKeys.Ascending(x => x.Bar));
          _myCollection.Indexes.CreateOne(indexDefinition, indexOptions);
      }
      

      查询时确保使用相同的排序规则:

      public IEnumerable<MyDto> GetItems()
      {
          var anyFilter = GetQueryFilter();
          var anySort = sortBuilder.Descending(x => x.StartsOn);  
          var findOptions = new FindOptions {Collation = _caseInsensitiveCollation};
      
          var result = _salesFeeRules
              .Find(anyFilter, findOptions)
              .Sort(anySort)
              .ToList();
      
          return result;
      }
      

      【讨论】:

        【解决方案8】:

        如果其他人想知道,使用 fluent-mongo 插件,您可以使用 Linq 进行这样的查询:

        public User FindByEmail(Email email)
        {
            return session.GetCollection<User>().AsQueryable()
                   .Where(u => u.EmailAddress.ToLower() == email.Address.ToLower()).FirstOrDefault();
        }
        

        这会导致正确的 JS 查询。不幸的是,尚不支持 String.Equals()。

        【讨论】:

        • 我想知道这在内部是如何工作的?我的印象是,唯一的方法是通过正则表达式(不能使用索引)和复制字段。
        • 查看源代码,它使用 .toLowerCase() 方法,没什么特别的。但是你让我担心索引。
        【解决方案9】:

        MongoDB 3.4+ 最简单的方法是使用 ICU 比较级别之一

        return await Collection()
        .Find(filter, new FindOptions { Collation = new Collation("en", strength: CollationStrength.Primary) })
        .ToListAsync();
        

        更多信息https://docs.mongodb.com/manual/reference/method/cursor.collation/index.html

        【讨论】:

        • 这对我不起作用。我假设您还需要为此建立一个索引。
        • 你不需要索引,而且效果很好,一切都在文档中。
        【解决方案10】:

        一种方法是使用 MongoDB.Bson.BsonJavaScript 类,如下所示

         store.FindAs<Property>(Query.Where(BsonJavaScript.Create(string.Format("this.City.toLowerCase().indexOf('{0}') >= 0", filter.City.ToLower()))));
        

        【讨论】:

        • 我可以这样做,但 javascript 无法使用索引。所以速度很慢。
        【解决方案11】:

        这是精确的文本搜索,不区分大小写(请参阅this link)。

        { “FieldName” : /^keywordHere$/i }
        

        【讨论】:

        • 我猜这是因为没有说明 C# 示例而被否决?
        猜你喜欢
        • 2015-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-31
        • 2021-02-03
        相关资源
        最近更新 更多