【问题标题】:How do I make case-insensitive queries on Mongodb?如何在 Mongodb 上进行不区分大小写的查询?
【发布时间】:2011-10-29 10:11:33
【问题描述】:
var thename = 'Andrew';
db.collection.find({'name':thename});

如何查询不区分大小写?即使是“andrew”,我也想找到结果;

【问题讨论】:

标签: regex mongodb database


【解决方案1】:

正则表达式查询将比基于索引的查询慢。

您可以创建具有特定排序规则的索引,如下所示
db.collection.createIndex({field:1},{collation: {locale:'en',strength:2}},{background : true});

上述查询将创建一个忽略字符串大小写的索引。需要为每个查询指定排序规则,以便它使用不区分大小写的索引。

查询
db.collection.find({field:'value'}).collation({locale:'en',strength:2});

注意 - 如果您没有为每个查询指定排序规则,查询将不会使用新索引。

请参阅此处的 mongodb 文档以获取更多信息 - https://docs.mongodb.com/manual/core/index-case-insensitive/

【讨论】:

    【解决方案2】:

    这将完美运行
    db.collection.find({ song_Name: { '$regex': searchParam, $options: 'i' } })

    只需添加您的正则表达式 $options: 'i' 其中 i 不区分大小写。

    【讨论】:

      【解决方案3】:

      ...在 NodeJS 上使用 mongoose 进行查询:

      const countryName = req.params.country;
      
      { 'country': new RegExp(`^${countryName}$`, 'i') };
      

      const countryName = req.params.country;
      
      { 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } };
      
      // ^australia$
      

      const countryName = req.params.country;
      
      { 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } };
      
      // ^turkey$
      

      一个完整的 Javascript 代码示例,NodeJS 和 Mongoose ORM 在 MongoDB 上

      // get all customers that given country name
      app.get('/customers/country/:countryName', (req, res) => {
          //res.send(`Got a GET request at /customer/country/${req.params.countryName}`);
      
          const countryName = req.params.countryName;
      
          // using Regular Expression (case intensitive and equal): ^australia$
      
          // const query = { 'country': new RegExp(`^${countryName}$`, 'i') };
          // const query = { 'country': { $regex: new RegExp(`^${countryName}$`, 'i') } };
          const query = { 'country': { $regex: new RegExp(`^${countryName}$`), $options: 'i' } };
      
          Customer.find(query).sort({ name: 'asc' })
              .then(customers => {
                  res.json(customers);
              })
              .catch(error => {
                  // error..
                  res.send(error.message);
              });
      });
      

      【讨论】:

      • 谢谢,第一种方法和第三种方法有什么区别?
      【解决方案4】:
      1. 使用 Mongoose(和 Node),这很有效:

        • User.find({ email: /^name@company.com$/i })

        • User.find({ email: new RegExp(`^${emailVariable}$`, 'i') })

      2. 在 MongoDB 中,这很有效:

        • db.users.find({ email: { $regex: /^name@company.com$/i }})

      这两行都不区分大小写。数据库中的电子邮件可能是NaMe@CompanY.Com,这两行仍然会在数据库中找到对象。

      同样,我们可以使用/^NaMe@CompanY.Com$/i,它仍然会在数据库中找到电子邮件:name@company.com

      【讨论】:

      • 谢谢雷蒙德。它工作User.find({ email: new RegExp(^${emailVariable}$, 'i') }) 示例
      【解决方案5】:

      要查找不区分大小写的字符串,请使用这个,

      var thename = "Andrew";
      db.collection.find({"name":/^thename$/i})
      

      【讨论】:

      【解决方案6】:

      一种简单的方法是使用 $toLower,如下所示。

      db.users.aggregate([
          {
              $project: {
                  name: { $toLower: "$name" }
              }
          },
          {
              $match: {
                  name: the_name_to_search
              }
          }
      ])
      

      【讨论】:

        【解决方案7】:

        您可以使用不区分大小写的索引

        以下示例创建一个没有默认排序规则的集合,然后使用不区分大小写的排序规则在名称字段上添加索引。 International Components for Unicode

        /*
        * strength: CollationStrength.Secondary
        * Secondary level of comparison. Collation performs comparisons up to secondary * differences, such as diacritics. That is, collation performs comparisons of 
        * base characters (primary differences) and diacritics (secondary differences). * Differences between base characters takes precedence over secondary 
        * differences.
        */
        db.users.createIndex( { name: 1 }, collation: { locale: 'tr', strength: 2 } } )
        

        要使用索引,查询必须指定相同的排序规则。

        db.users.insert( [ { name: "Oğuz" },
                                    { name: "oğuz" },
                                    { name: "OĞUZ" } ] )
        
        // does not use index, finds one result
        db.users.find( { name: "oğuz" } )
        
        // uses the index, finds three results
        db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 2 } )
        
        // does not use the index, finds three results (different strength)
        db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 1 } )
        

        或者您可以使用默认排序规则创建一个集合:

        db.createCollection("users", { collation: { locale: 'tr', strength: 2 } } )
        db.users.createIndex( { name : 1 } ) // inherits the default collation
        

        【讨论】:

          【解决方案8】:

          要查找不区分大小写的文字字符串:

          使用正则表达式(推荐)

          db.collection.find({
              name: {
                  $regex: new RegExp('^' + name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '$', 'i')
              }
          });
          

          使用小写索引(更快)

          db.collection.find({
              name_lower: name.toLowerCase()
          });
          

          正则表达式比文字字符串匹配慢。但是,额外的小写字段会增加您的代码复杂性。如有疑问,请使用正则表达式。如果它可以替换您的字段,我建议仅使用明确的小写字段,也就是说,您首先不关心大小写。

          请注意,您需要在正则表达式之前对名称进行转义。如果您想要用户输入通配符,最好在转义后附加.replace(/%/g, '.*'),以便匹配“a%”以查找所有以“a”开头的名称。

          【讨论】:

            【解决方案9】:

            您需要为此使用不区分大小写的regular expression,例如

            db.collection.find( { "name" : { $regex : /Andrew/i } } );
            

            要使用thename 变量中的正则表达式模式,请构造一个新的RegExp 对象:

            var thename = "Andrew";
            db.collection.find( { "name" : { $regex : new RegExp(thename, "i") } } );
            

            更新:对于完全匹配,您应该使用正则表达式 "name": /^Andrew$/i。感谢 Yannick L。

            【讨论】:

            • 你知道如何使用 Node.js mongoose 做到这一点吗?
            • 我想知道这对大型收藏品的效果如何。你会失去排序功能的好处
            • 这是错误的,它会匹配任何包含 "andrew" for name 的文档,而不仅仅是等于。
            • @JonathanCremin 来帮助您应该发布正确答案的人:{ "name": /^Andrew$/i }
            • @YannickL。 1+ 用于做常识性的事情。我只是路过而不是我想要的。
            【解决方案10】:

            MongoDB 3.4 现在包含创建真正不区分大小写索引的功能,这将大大提高在大型数据集上不区分大小写查找的速度。它是通过指定强度为 2 的排序规则生成的。

            可能最简单的方法是在数据库上设置排序规则。然后所有查询都会继承该排序规则并使用它:

            db.createCollection("cities", { collation: { locale: 'en_US', strength: 2 } } )
            db.names.createIndex( { city: 1 } ) // inherits the default collation
            

            你也可以这样做:

            db.myCollection.createIndex({city: 1}, {collation: {locale: "en", strength: 2}});
            

            并像这样使用它:

            db.myCollection.find({city: "new york"}).collation({locale: "en", strength: 2});
            

            这将返回名为“new york”、“New York”、“New york”等的城市。

            欲了解更多信息:https://jira.mongodb.org/browse/SERVER-90

            【讨论】:

            【解决方案11】:

            以下查询将查找具有所需字符串的文档不敏感且全局出现

            db.collection.find({name:{
                                         $regex: new RegExp(thename, "ig")
                                     }
                                },function(err, doc) {
                                                     //Your code here...
                              });
            

            【讨论】:

              【解决方案12】:

              我已经这样解决了。

               var thename = 'Andrew';
               db.collection.find({'name': {'$regex': thename,$options:'i'}});
              

              如果你想查询“不区分大小写的精确匹配”,那么你可以这样。

              var thename =  '^Andrew$';
              db.collection.find({'name': {'$regex': thename,$options:'i'}});
              

              【讨论】:

                【解决方案13】:

                我几个小时前刚刚解决了这个问题。

                var thename = 'Andrew'
                db.collection.find({ $text: { $search: thename } });
                
                • 以这种方式进行查询时,默认情况下区分大小写和变音符号的敏感性设置为 false。

                您甚至可以通过从 Andrew 的用户对象中选择您需要的字段来扩展此功能:

                db.collection.find({ $text: { $search: thename } }).select('age height weight');
                

                参考:https://docs.mongodb.org/manual/reference/operator/query/text/#text

                【讨论】:

                • $text 对使用文本索引索引的字段的内容执行文本搜索。
                【解决方案14】:

                Chris Fulstow 的解决方案可行 (+1),但它可能效率不高,尤其是在您的收藏非常大的情况下。无根正则表达式(那些不以^ 开头的正则表达式,它将正则表达式锚定到字符串的开头),以及那些使用i 标志以区分大小写的正则表达式将不会使用索引,即使它们存在。

                您可能考虑的另一种选择是将数据非规范化以存储name 字段的小写版本,例如name_lower。然后,您可以有效地查询(特别是如果它被索引)不区分大小写的完全匹配,例如:

                db.collection.find({"name_lower": thename.toLowerCase()})
                

                或者与前缀匹配(一个有根的正则表达式)为:

                db.collection.find( {"name_lower":
                    { $regex: new RegExp("^" + thename.toLowerCase(), "i") } }
                );
                

                这两个查询都将使用name_lower 上的索引。

                【讨论】:

                • 很好的答案,我的正则表达式方法在扫描数百万个文档时确实会变慢。
                • 这实际上并不完全正确,因为您可能会在查找“Andrew”时找到“Andrew something”。因此,将正则表达式调整为:new RegExp('^'+ username + '$', "i") 以完全匹配。
                • 根据 MongoDB 网站,任何不区分大小写的正则表达式都不是索引有效的“当正则表达式在字符串的开头(即 ^)具有锚点并且是 区分大小写匹配"
                • 使用 Mongoose 这对我有用: User.find({'username': {$regex: new RegExp('^' + username.toLowerCase(), 'i')}}, function( err, res){ if(err) throw err; next(null, res); });
                • 在使用正则表达式时不要忘记转义名称。我们不希望注射取代 mongodb 的美丽。想象一下,您将此代码用于登录页面,并且用户名是 ".*"
                猜你喜欢
                • 1970-01-01
                • 2010-12-24
                • 1970-01-01
                • 2019-05-21
                • 2011-10-23
                • 1970-01-01
                相关资源
                最近更新 更多