示例:

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

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


评论

从MongoDB 3.2开始,您可以使用$ caseSensitive:false执行不区分大小写的搜索。参见:docs.mongodb.org/manual/reference/operator/query/text/…

请注意,这仅在文本索引上。

@martin:$ caseSensitive默认情况下已经为false,并且不能回答问题,因为它仅适用于索引字段。 OP一直在寻找不区分大小写的字符串比较。

找到重复项的最佳选择:stackoverflow.com/questions/40978162/…

#1 楼

您可以使用正则表达式。

在您的示例中为:

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


但是,我必须说,也许您可​​以在转换过程中小写(或大写)该值,而不是每次发现它都会产生额外的成本。显然,这不适用于人们的名字等等,但也许像标签这样的用例。

评论


这很完美。通过以下方式在PHP中工作:$ collection-> find(array('key'=> new MongoRegex('/'.$ val。'/ i'))));

–路易斯·丹尼斯(Luke Dennis)
2009年12月9日下午4:22

特别是如果您要内插一个可能带有问号的字符串({foo:/#{x} / i})。

– Peter Ehrlich
2011-12-16 18:53

也不要忘记^和$:MongoRegex('/ ^'。preg_quote($ val)。'$ / i')

–朱利安
13年1月1日于20:26

请注意,这将执行全扫描而不是使用索引。

– Martin Konicek
13年4月25日在13:29

如果他在开始时使用^锚,则不会进行完全扫描,因此,朱利安建议的重要性。

– Pax
13年7月6日在22:37

#2 楼

更新:

原来的答案现在已经过时了。 Mongodb现在支持具有许多功能的高级全文搜索。

原始答案:

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

即使是小型数据集,它也不是很有效。您要获得的CPU命中率要比查询凭单大得多,如果要实现规模化,这可能会成为一个问题。例如,我有一个User表,其中的用户名是大小写混合的,但是id是用户名的大写副本。这确保了区分大小写的复制是不可能的(不允许同时使用“ Foo”和“ foo”),并且我可以通过id = username.toUpperCase()进行搜索,以获取不区分大小写的用户名搜索。

如果您的字段很大(例如消息正文),则复制数据可能不是一个好的选择。我认为在这种情况下,使用像Apache Lucene这样的无关紧要的索引器是最好的选择。

评论


我最近在mongodb 3.0.4上测试了100,000条带有索引名称字段的记录。不区分大小写的正则表达式查询需要200毫秒以上的时间,而区分大小写的正则表达式大约需要16毫秒(两种情况都包括以'^'开头的正则表达式)

– dCoder
2015年12月6日,7:44

文件可能已更新。他们现在说:“对于区分大小写的正则表达式查询,如果该字段存在索引,则MongoDB将正则表达式与索引中的值进行匹配,这可能比集合扫描更快。”

–杰夫·刘易斯
16年8月25日在22:24

文本索引的另一个限制是每个集合只能有一个(多列),因此如果您需要针对不同的情况在不同的字段中隔离搜索,则不适合。

–Paul Grimshaw
17年4月28日在16:43



@SergiySokolenko:文档现在说(该节的最后一段):“不区分大小写的正则表达式查询通常不能有效地使用索引。$ regex实现不支持排序规则,并且不能使用不区分大小写的索引。”

– Dan Dascalescu
19年5月13日在5:27

在这种情况下,使用全文搜索是错误的(并且可能是危险的),因为问题在于是否进行不区分大小写的查询,例如username:与Bill或Bill匹配的'bill',不是全文搜索查询,也将与bill的词干匹配,例如Bills,billed等。

– Dan Dascalescu
19年5月13日在5:32

#3 楼

从MongoDB 3.4开始,推荐的执行不区分大小写的快速搜索的方法是使用不区分大小写的索引。自2009年以来,这一直是JIRA的问题,许多人都要求使用此功能。它的工作方式如下:
通过指定强度为1或2的排序规则来创建不区分大小写的索引。您可以像这样创建不区分大小写的索引:
 db.cities.createIndex(
  { city: 1 },
  { 
    collation: {
      locale: 'en',
      strength: 2
    }
  }
);
 

创建集合时,您还可以为每个集合指定默认排序规则:不敏感的索引,您需要在创建索引或集合时使用的find操作中指定相同的排序规则:
 db.cities.find(
  { city: 'new york' }
).collation(
  { locale: 'en', strength: 2 }
);
 

这将返回“纽约”,“纽约”,“纽约”等。
其他说明


建议使用全文搜索的答案在这种情况(可能有危险)。问题是关于不区分大小写的查询,例如username: 'bill'匹配BILLBill,而不是全文搜索查询,也将匹配bill的词干(例如Billsbilled等)。建议使用正则表达式的答案是速度很慢,因为即使使用索引,该文档也指出:“不区分大小写的正则表达式查询通常不能有效地使用索引。$ regex实现不支持排序规则,并且不能使用不区分大小写的索引。 “

$regex答案还会冒着用户输入注入的风险。



评论


即使使用聚合管道,对我来说也很棒。

– Morio
19年4月16日在14:16

我认为这是正确的答案,因为数据读取速度很重要

– Rndmax
19-10-11在7:59

创建集合后,我似乎找不到任何将默认排序规则添加到集合的方法。有什么办法吗?

– IncrediblePony
6月3日12:41

#4 楼

如果需要从变量创建正则表达式,这是一种更好的方法: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 } );


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

评论


新的RegExp(“ ^” + req.params.term.toLowerCase(),“ i”)也可以正常工作

–塔希尔·亚辛(Tahir Yasin)
17 Mar 29 '17在15:43

如果变量来自请求,则应考虑转义字符串以提高安全性:stackoverflow.com/a/50633536/5195127

–davidivad
18年5月31日在22:19

从MongoDB 3.4开始,对不区分大小写的索引提供了本机支持

– Dan Dascalescu
19年5月13日在6:59

#5 楼

请记住,前面的示例:

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


将导致每个包含bar的条目都与查询匹配(bar1,barxyz,openbar),对于通过auth函数进行用户名搜索...

您可能需要使用适当的regexp语法,使其仅与搜索词匹配:

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


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

评论


这个答案看起来像一条评论。

– Dan Dascalescu
19年5月12日在22:52

#6 楼

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


评论


发布此答案之前,您是否查看过现有答案?您可能想要解释与以前的答案相比,它如何增加一些有价值的东西,而不是准重复的仅代码答案。

– Dan Dascalescu
19年5月12日在22:56



我只想补充一下,这个答案使我找到了解决方案。我使用的是PHP框架,它很好地适合ORM语法,而这里的其他解决方案则没有。 $ existing = Users :: masterFind('all',['conditions'=> ['traits.0.email'=> ['$ regex'=>“ ^ $ value $”,'$ options'=>'i ']]]);

– Don Rzeszut
19 Sep 12'在17:41



只是想重申一下,使用$ regex这样会引起集合扫描,尤其是当您使用“ ^ ... $”时。完整说明可在此处的Mongo链接上找到。随着收藏的增长,性能将受到重大影响。

–InitialV
8月20日3:05

#7 楼

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


评论


@ OlegV.Volkov必须具有有关您的答案如何合适以及发问者代码中有什么问题的描述。

–Parth Trivedi
2015年12月18日下午4:39

这个仅提供代码的答案不会在6年前发布的已接受答案中添加任何内容。

– Dan Dascalescu
19年5月12日在22:54

#8 楼

TL; DR
在mongo中执行此操作的正确方法
请勿使用RegExp
变得自然并使用mongodb的内置索引编制,搜索
步骤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


 


评论


一个不错的选择,但是使用文本索引和正则表达式没有什么“正确”的选择,这只是另一种选择。对于OP来说,这太过分了。

–JohnnyHK
16年8月28日在2:16

除了正则表达式要慢得多。全文搜索也很慢,但并不慢。最快(但更肿)的方式是将始终设置为小写的单独字段。

–汤姆·梅塔姆(Tom Mettam)
18年1月17日,0:37

在这种情况下,使用全文搜索是错误的(并且可能是危险的),因为问题在于是否进行不区分大小写的查询,例如username:与Bill或Bill匹配的'bill',不是全文搜索查询,也将与bill的词干匹配,例如Bills,billed等。

– Dan Dascalescu
19年5月13日在5:32

#9 楼

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

评论


只是为了澄清这一点:对索引字段允许不区分大小写的搜索,它们将不使用索引,并且速度会慢于未索引字段的速度。

–heavi5ide
2011-12-19 17:22

@ heavi5ide,因为此问题用于标记重复项,所以我想澄清一下正则表达式(不区分大小写的搜索需要)确实使用了索引,但是,它们必须进行完整的索引扫描。换句话说,他们不能有效地使用索引。幸运的是,此文档自2011年以来已进行了更新,但在此也要特别注意。

– Sammaye
2014年8月13日17:37



#10 楼

使用基于Regex的查询时要记住的一件事很重要-在登录系统中执行此操作时,请转义要搜索的每个字符,并且不要忘记^和$运算符。 Lodash为此提供了一个很好的功能,您是否应该已经使用它:

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


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

#11 楼

假设您要在“表格”中搜索“列”,并且要进行区分大小写的搜索。最好和有效的方法如下; br />
一切顺利。

#12 楼

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

每次再次保存该对象时,都将检查小写字母属性并更新其主要属性。这样一来,您就可以有效地进行搜索,但隐藏每次更新lc字段所需的额外工作。前缀lc_。我使用第二个来简化查询(深对象查询有时会令人困惑)。

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

评论


不错的解决方案,但幸运的是从MongoDB 3.4开始,对不区分大小写的索引提供了本机支持。

– Dan Dascalescu
19年5月13日在7:00

#13 楼

使用猫鼬对我有用:

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


评论


如果要指定i的不区分大小写的标志,.toLowerCase()是否不是多余的?

–k00k
15年7月1日在15:01

是的。您不需要.toLowerCase()。我已将其从答案中删除。

–克里斯里​​奇
17年5月18日1:00



嗯,这应该那样工作吗?当我搜索“ mark”时,它也会获得带有“ marko”的所有记录-有没有办法只忽略大小写敏感?

–瑞士
17年6月19日,0:54

确定,正确的正则表达式为:'^'+ serach_name +'$',“ i”

–瑞士
17年6月19日在1:02

这很危险。您没有在转义用户名,因此可以插入任意正则表达式。

–汤姆·梅塔姆(Tom Mettam)
18年1月17日,0:37

#14 楼

聚合框架是在mongodb 2.2中引入的。您可以使用字符串运算符“ $ strcasecmp”在字符串之间进行不区分大小写的比较。与使用正则表达式相比,它更推荐并且更容易使用。

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

评论


如何在find()查询中使用它? db.stuff.find({name:$ strcasecmp(name)})吗?

–瑞士
17年6月19日在0:51

#15 楼

要搜索变量并对其进行转义:

const escapeStringRegexp = require('escape-string-regexp')
const name = 'foo'
db.stuff.find({name: new RegExp('^' + escapeStringRegexp(name) + '$', 'i')})   


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

转义字符串正则表达式

#16 楼

您可以使用不区分大小写的索引:下面的示例创建一个不带默认排序规则的集合,然后在不区分大小写的排序规则的name字段上添加一个索引。 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


评论


似乎存在较小的语法问题(缺少大括号)。请更新查询:db.users.createIndex({name:1},{collat​​ion:{locale:'tr',strength:2}})

– Mohd Belal
18年4月12日在11:56



#17 楼

使用RegExp,
如果其他任何选项都不适合您,RegExp是一个不错的选择。它使字符串不区分大小写。

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


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

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

#18 楼

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

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


然后您只需按如下所示过滤字段即可。 >
db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();


#19 楼

在C#中,使用过滤器对我有用。

这也避免了mongodb会认为p.Title.ToLower()是一个属性并获得胜利的问题。映射不正确。

评论


谢谢,它为我工作。在这里,我们需要获取变量中的过滤器,然后传入Find()方法。

– Nilay
18年8月25日在11:33

#20 楼

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

#21 楼

我感到惊讶的是,如果bar是密码或帐户ID搜索,则没有人通过使用/^bar$/i来警告正则表达式注入的风险。 (例如bar => .*@myhackeddomain.com,所以我敢打赌:请使用PERL中提供的\Q \E regex特殊字符! >另一种选择是使用正则表达式转义字符策略,例如此处所述的Java等效于Perl的\ Q ... \ E或quotemeta()

#22 楼

如您在mongo文档中所见-由于版本3.2 $text的索引默认不区分大小写:https://docs.mongodb.com/manual/core/index-text/#text-index-case-insensitiveivity

创建一个文本索引并在查询中使用$ text运算符。

评论


在这种情况下,使用全文搜索是错误的(并且可能是危险的),因为问题在于是否进行不区分大小写的查询,例如username:与Bill或Bill匹配的'bill',不是全文搜索查询,也将与bill的词干匹配,例如Bills,billed等。

– Dan Dascalescu
19年5月13日在5:34

#23 楼

这些已针对字符串搜索进行了测试

{'_id': /.*CM.*/}               ||find _id where _id contains   ->CM
{'_id': /^CM/}                  ||find _id where _id starts     ->CM
{'_id': /CM$/}                  ||find _id where _id ends       ->CM

{'_id': /.*UcM075237.*/i}       ||find _id where _id contains   ->UcM075237, ignore upper/lower case
{'_id': /^UcM075237/i}          ||find _id where _id starts     ->UcM075237, ignore upper/lower case
{'_id': /UcM075237$/i}          ||find _id where _id ends       ->UcM075237, ignore upper/lower case


#24 楼

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

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


评论


该解决方案之前已经给出过两次。在发布新答案之前,请检查现有答案。

– Dan Dascalescu
19年5月13日下午5:36

@DanDascalescu不知道您在说什么,在CTRL + F上,类似的解决方案在2018年9月发布了我。我在2018年4月发布了我的答案。在警告那些真正尝试提供帮助的人之前,还请检查它的发布时间。

– Woppi
19年5月16日在6:51



我说的是2016年4月的答案,以及2016年5月的答案。两者都使用$ regex和$ options。您按了Ctrl + F了什么?

– Dan Dascalescu
19年5月16日在7:17

另外,使用$ regex效率低下并且可能不安全,正如我在2016年其他答案中所做的解释中所述。如果答案不再为社区服务,删除它们就不会感到羞耻!

– Dan Dascalescu
19年5月16日在7:19

注意到效率低下的$ regex,非常感谢。我按Ctrl + F $ options。我们只有两个,在$ regex代码中没有新的Regexp,分别为2018年4月和2018年9月。我没有在答案中使用新的Regexp。我忘记了新Regexp遇到的特定问题,将其删除后就解决了,只使用我发布的解决方案即可。

– Woppi
19年5月16日在9:17