MongoDB:是否可以进行不区分大小写的查询?

时间:2009-12-07 22:36:37

标签: mongodb case-insensitive

示例:

> db.stuff.save({"foo":"bar"});

> db.stuff.find({"foo":"bar"}).count();
1
> db.stuff.find({"foo":"BAR"}).count();
0

23 个答案:

答案 0 :(得分:297)

您可以使用regex

在您的示例中:

db.stuff.find( { foo: /^bar$/i } );

但我必须说,也许你可以在途中放下(或者说是)价值,而不是每次发现它都会产生额外的费用。显然,这不适用于人们的姓名等,但可能是像标签这样的用例。

答案 1 :(得分:190)

<强>更新

原来的答案现在已经过时了。 Mongodb now supports advanced full text searching, with many features.

原始答案:

应该注意的是,使用正则表达式不区分大小写/ i进行搜索意味着mongodb无法按索引进行搜索,因此针对大型数据集的查询可能需要很长时间。

即使使用小型数据集,它也不是很有效。你的cpu命中率远高于你的查询保证,如果你试图达到规模,这可能会成为一个问题。

作为替代方案,您可以存储大写副本并对其进行搜索。例如,我有一个User表,其用户名是大小写混合的,但id是用户名的大写副本。这样可以确保区分大小写的复制是不可能的(不允许使用“Foo”和“foo”),我可以通过id = username.toUpperCase()进行搜索,以获得对用户名不区分大小写的搜索。

如果您的字段很大,例如邮件正文,则复制数据可能不是一个好选择。我相信在这种情况下使用像Apache Lucene这样无关的索引器是最好的选择。

答案 2 :(得分:58)

请记住上一个示例:

db.stuff.find( { foo: /bar/i } );

会导致包含 bar 的每个条目与查询(bar1,barxyz,openbar)匹配,在auth函数上进行用户名搜索可能会非常危险......

您可能需要使用相应的正则表达式语法使其仅匹配搜索词:

db.stuff.find( { foo: /^bar$/i } );

有关正则表达式的语法帮助,请参阅http://www.regular-expressions.info/

答案 3 :(得分:56)

如果您需要从变量创建正则表达式,这是一种更好的方法:https://stackoverflow.com/a/10728069/309514

然后您可以执行以下操作:

var string = "SomeStringToFind";
var regex = new RegExp(["^", string, "$"].join(""), "i");
// Creates a regex of: /^SomeStringToFind$/i
db.stuff.find( { foo: regex } );

如果您经常重复使用,那么这样做的好处就是更具编程性,或者您可以通过提前编译来提升性能。

答案 4 :(得分:31)

从MongoDB开始,执行快速不区分大小写搜索的推荐方法是使用 Case Insensitive Index

我亲自通过电子邮件向其中一位创始人发送电子邮件以取悦这项工作,他实现了这一目标!它是issue on JIRA since 2009,许多人都要求使用该功能。以下是它的工作原理:

通过指定强度为1或2的collation来创建不区分大小写的索引。您可以创建不区分大小写的索引,如下所示:

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

您还可以在创建每个集合时指定默认排序规则:

db.createCollection('cities', { collation: { locale: 'en', strength: 2 } } );

在任何一种情况下,为了使用不区分大小写的索引,您需要在创建索引或集合时使用的find操作中指定相同的排序规则:

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

这将返回“纽约”,“纽约”,“纽约”等。

其他说明

  • 在这种情况下,建议使用全文搜索的答案是错误的(并且可能是危险的)。问题是关于进行不区分大小写的查询,例如username: 'bill'匹配BILLBill,而不是全文搜索查询,该查询也会匹配bill的{​​{3}}个字词,例如Billsbilled等。
  • 建议使用正则表达式的答案很慢,因为即使使用索引,stemmed

      

    “不区分大小写的正则表达式查询通常无法有效使用索引。$ regex实现不支持排序规则,并且无法使用不区分大小写的索引。”

    $regex个答案也存在documentation states的风险。

答案 5 :(得分:16)

db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity

答案 6 :(得分:14)

TL; DR

在mongo中执行此操作的正确方法

请勿使用 RegExp

Go natural And use mongodb's inbuilt indexing , search

第1步:

db.articles.insert(
   [
     { _id: 1, subject: "coffee", author: "xyz", views: 50 },
     { _id: 2, subject: "Coffee Shopping", author: "efg", views: 5 },
     { _id: 3, subject: "Baking a cake", author: "abc", views: 90  },
     { _id: 4, subject: "baking", author: "xyz", views: 100 },
     { _id: 5, subject: "Café Con Leche", author: "abc", views: 200 },
     { _id: 6, subject: "Сырники", author: "jkl", views: 80 },
     { _id: 7, subject: "coffee and cream", author: "efg", views: 10 },
     { _id: 8, subject: "Cafe con Leche", author: "xyz", views: 10 }
   ]
)

第2步:

需要在要搜索的 TEXT 字段上创建索引,而不进行索引查询会非常慢

db.articles.createIndex( { subject: "text" } )

第3步:

db.articles.find( { $text: { $search: "coffee",$caseSensitive :true } } )  //FOR SENSITIVITY
db.articles.find( { $text: { $search: "coffee",$caseSensitive :false } } ) //FOR INSENSITIVITY

答案 7 :(得分:8)

Mongo(当前版本2.0.0)不允许对索引字段进行不区分大小写的搜索 - 请参阅their documentation。对于非索引字段,其他答案中列出的正则表达式应该没问题。

答案 8 :(得分:7)

db.company_profile.find({ "companyName" : { "$regex" : "Nilesh" , "$options" : "i"}});

答案 9 :(得分:6)

最好的方法是用您选择的语言,在为对象创建模型包装器时,让save()方法遍历您将要搜索的一组字段,这些字段也被索引;那些字段集应该有小写的对应字符,然后用于搜索。

每次再次保存对象时,都会检查小写属性,并使用对主要属性的任何更改进行更新。这将使您可以高效搜索,但隐藏每次更新lc字段所需的额外工作。

小写字段可以是键:值对象存储或只是带有前缀lc_的字段名称。我使用第二个来简化查询(深层对象查询有时会令人困惑)。

注意:您要索引lc_字段,而不是它们所基于的主要字段。

答案 10 :(得分:5)

使用Mongoose这对我有用:

var find = function(username, next){
    User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){
        if(err) throw err;
        next(null, res);
    });
}

答案 11 :(得分:5)

假设您要在“表格”中搜索“列”,并且您希望不区分大小写搜索。最好和最有效的方法如下;

//create empty JSON Object
mycolumn = {};

//check if column has valid value
if(column) {
    mycolumn.column = {$regex: new RegExp(column), $options: "i"};
}
Table.find(mycolumn);

以上代码只是将您的搜索值添加为RegEx,并使用设置为“i”的insensitve条件作为选项进行搜索。

一切顺利。

答案 12 :(得分:5)

使用基于Regex的查询时要记住的一件非常重要的事情 - 当您为登录系统执行此操作时,您正在搜索escape every single character,并且不要忘记^和$运算符。 Lodash has a nice function for this,您是否应该使用它:

db.stuff.find({$regex: new RegExp(_.escapeRegExp(bar), $options: 'i'})

为什么呢?想象一下,用户输入.*作为他的用户名。这将匹配所有用户名,只需猜测任何用户的密码即可启用登录。

答案 13 :(得分:3)

聚合框架是在mongodb 2.2中引入的。你可以使用字符串运算符&#34; $ strcasecmp&#34;在字符串之间进行不区分大小写的比较。它比使用正则表达式更值得推荐和使用。

这里是聚合命令运算符的官方文档:https://docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/#exp._S_strcasecmp

答案 14 :(得分:2)

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

以下示例创建一个没有默认排序规则的集合,然后在名称字段上添加一个不区分大小写的排序规则的索引。 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

答案 15 :(得分:2)

搜索变量并转义它:

type mismatch;
 found   : PersonRepository.this.dbConfig.profile.ProfileAction[Option[Int],PersonRepository.this.dbConfig.profile.api.NoStream,slick.dbio.Effect.Read]
    (which expands to)  slick.sql.FixedSqlAction[Option[Int],slick.dbio.NoStream,slick.dbio.Effect.Read]
 required: slick.dbio.DBIOAction[models.Person,slick.dbio.NoStream,Nothing]

转义变量可以保护查询免受“。*”或其他正则表达式的攻击。

documentation

答案 16 :(得分:0)

我为不区分大小写的正则表达式创建了一个简单的Func,我在我的过滤器中使用了它。

private Func<string, BsonRegularExpression> CaseInsensitiveCompare = (field) => 
            BsonRegularExpression.Create(new Regex(field, RegexOptions.IgnoreCase));

然后,您只需按如下方式过滤字段。

db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();

答案 17 :(得分:0)

使用过滤器可以在C#中使用。

string s = "searchTerm";
    var filter = Builders<Model>.Filter.Where(p => p.Title.ToLower().Contains(s.ToLower()));
                var listSorted = collection.Find(filter).ToList();
                var list = collection.Find(filter).ToList();

它甚至可能使用索引,因为我相信在返回发生后调用这些方法,但我还没有测试过。

这也避免了

的问题
var filter = Builders<Model>.Filter.Eq(p => p.Title.ToLower(), s.ToLower());

mongodb会认为p.Title.ToLower()是一个属性,无法正确映射。

答案 18 :(得分:0)

对于使用Golang并希望使用mongodb和mgo godoc globalsign library进行区分大小写的全文本搜索的人。

arrayBoxes.get(i).xcoordi

答案 19 :(得分:0)

令我惊讶的是,如果 bar 是密码或帐户ID搜索,没有人警告使用/^bar$/i进行正则表达式注入的风险。 (例如bar => .*@myhackeddomain.com,所以我押注:使用PERL中提供的\Q \E正则表达式特殊字符!

db.stuff.find( { foo: /^\Qbar\E$/i } );

您应将{em> bar 变量\\\一起转义,以避免\E在例如bar = '\E.*@myhackeddomain.com\Q'

另一种选择是使用正则表达式转义字符策略,例如此处Javascript equivalent of Perl's \Q ... \E or quotemeta()

答案 20 :(得分:-1)

正如您在mongo文档中看到的那样 - 因为版本3.2 $text索引默认情况下不区分大小写:https://docs.mongodb.com/manual/core/index-text/#text-index-case-insensitivity

Create a text indexuse $text operator in your query

答案 21 :(得分:-1)

我遇到过类似的问题,这对我有用:

  const flavorExists = await Flavors.findOne({
    'flavor.name': { $regex: flavorName, $options: 'i' },
  });

答案 22 :(得分:-1)

使用 RegExp ,  万一其他选项对您不起作用,RegExp是个不错的选择。它使字符串区分大小写。

var username = new RegExp("John", "i");

username的值将类似于/John/i

在查询中使用用户名,然后完成操作。

我希望它也对您有用。祝一切顺利。