java mongo忽略大小写,MongoDB:是否可以进行不区分大小写的查询?

例子:

> 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/…

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

@马丁:默认情况下,$caseSensitive已经是假的了,这并不能回答这个问题,因为它只在索引字段上工作。OP正在寻找不区分大小写的字符串比较。

你可以用正则表达式。

在您的示例中:

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

不过,我必须说,也许你可以在进入的过程中降低(或提高)价值,而不是每次你发现它都要承担额外的成本。很明显,这对人名之类的人不起作用,但也可能是像标签这样的用例。

这很管用。让它在php中使用:$collection->find(array('key'=>new mongoregex('/'$val.'/i'));

尤其是当你在插入一个字符串(foo/x/i),其中可能有问号。

别忘了加上preg_引号()。

别忘了^和$:MongoRegex('/^'。普雷格报价($val)。美元/我)

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

如果他一开始就使用锚定,就不会进行全面扫描,因此朱利安的建议很重要。

嘿,我跟着朱利安。但是,无法得到结果。之后,我跟着卢克·丹尼斯。我得到了结果。请给我建议。哪一个在技术上是正确的?

这对我有用,谢谢。是的,预售/预售是一个很好的建议。

我必须做:array("key"=>array("$regex"=>new mongoregex("/^")。瓦尔。$/i));

我看不出这根绳子的上下套管有多大帮助。如果数据库中的值为"foo",并且您正在搜索"foo"或"foo",则两者都不匹配。它不像传统的SQL那样,在变量中有db字段,并且可以将搜索字符串和db字符串都小写。我是否遗漏了一些明显的东西?

它们的意思是将存储在数据库上的值小写("foo"而不是"foo")—而不是查询。这可能需要在文档中添加一个特殊的"search"值:"myvalue":"foo","searchable":"foo"

如果试图检查包含regex相关字符的字符串,则此方法不起作用。例如问号或星号。

@你可以像往常一样简单地避开那些角色。/this\/has\/slashes\//

"对于不区分大小写的正则表达式查询,这些查询通常不能有效地使用索引。"->docs.mongodb.com/manual/reference/operator/query/regex

regex可以工作,但它们会应用regex扫描整个数据库,而不使用索引。什么是很有感情的

从MongoDB3.4开始,有一个更快更合适的解决方案:不区分大小写的索引。还有@pax,这是不正确的。请参阅SEBPIQ发布的参考资料。

更新:

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

原始答案:

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

即使是小数据集,它也不是很有效。您的CPU命中率远远高于查询要求,如果您试图实现规模,这可能会成为一个问题。

作为一种替代方法,您可以存储一个大写的副本并对其进行搜索。例如,我有一个用户表,它有一个混合大小写的用户名,但ID是用户名的大写副本。这确保了不可能进行区分大小写的复制(不允许同时使用"foo"和"foo"),并且我可以通过id=username.touppercase()进行搜索,以获得对username不区分大小写的搜索。

如果您的字段很大,例如消息体,那么复制数据可能不是一个好的选择。我相信在这种情况下,使用像ApacheLucene这样的无关索引器是最好的选择。

有没有显示索引如何工作的文档?我问是因为,如果我记得的话,MarkLogic能够保存一个额外的不区分大小写的索引…也许蒙古人也这么做?

Raymo,一个不区分大小写的索引特性,在蒙古人中并不存在,但它正在被讨论中。jira.mongodb.org/browse/server-90

@dan,最新mongodb中的信息是,"如果存在字段的索引,那么mongodb将正则表达式与索引中的值进行匹配,这比集合扫描更快。"--docs.mongodb.org/manual/reference/operator/query/regex/…

@丹,应该指出的是,这种新颖的全文索引有它的问题——"对于拉丁字母来说,文本索引对非发音符号不区分大小写,即对[a-z]不区分大小写。"对于所有其他字符,文本索引都将它们视为不同的。";因此,对于非拉丁字母表,使用regex搜索可能是合理的,它还应该利用现有索引(请参见上面的注释)。

我最近用MongoDB3.0.4测试了100000条记录,其中有一个名称字段被索引。不区分大小写的regex查询超过200毫秒,而区分大小写的regex大约需要16毫秒(这两种情况都包括以"^"开头的regex)。

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

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

这很酷,但StackOverflow的答案并不期望有20页的链接转储。扔掉一个TL;医生?指数似乎也与OP的要求不相关。

注意,它是基于索引的,这意味着在聚合框架中,它只支持第一层管道(可能第二层管道依赖于管道),在其他层中它是不可用的。

@sergiysokolenko:文档现在说(本节最后一段):"不区分大小写的正则表达式查询通常不能有效地使用索引。$regex实现不支持排序规则,因此无法使用不区分大小写的索引。"

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

请记住,前面的示例:

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

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

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

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

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

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

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

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

new RegExp("^" + req.params.term.toLowerCase(),"i")也很好用

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

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

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

我亲自给其中一位创始人发了邮件,希望他能成功完成这项工作!自2009年以来,这是一个关于JIRA的问题,许多人都要求使用该功能。工作原理如下:

通过指定强度为1或2的排序规则来创建不区分大小写的索引。您可以这样创建不区分大小写的索引:

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 }

);

这将返回"纽约"、"纽约"、"纽约"等。其他音符

在这种情况下,建议使用全文搜索的答案是错误的(而且可能很危险)。问题是要进行不区分大小写的查询,例如,与BILL或BILL匹配的username: 'bill',而不是与BILL的词干匹配的全文搜索查询,如Bills和billed等。

建议使用正则表达式的答案很慢,因为即使使用索引,文档也说明:

"Case insensitive regular expression queries generally cannot use indexes effectively. The $regex implementation is not collation-aware and is unable to utilize case-insensitive indexes."

$regex的答案也存在用户输入注入的风险。

对我来说工作得很好,即使是使用聚合管道。

db.zipcodes.find({city :"NEW YORK"}); // Case-sensitive

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

请在代码中添加说明。

@parthtrivedi,注释和代码本身一样长。你想要3页的论文还是什么?

@volkov必须描述你的答案是如何恰当的,以及提问者代码中有什么错误。

这个仅限代码的答案并没有为6年前发布的已接受答案添加任何内容。

DR在蒙古人做这个的正确方法

不使用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:

需要在要搜索的任何文本字段上创建索引,而不创建索引查询将非常慢。

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

很好的选择,但是使用文本索引和regex相比没有什么"正确"的,这只是另一个选择。这对手术来说太过分了。

除了regex明显慢。全文搜索也很慢,但不是很慢。最快(但更夸张)的方法是将一个单独的字段设置为小写。

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

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

为了澄清这一点:在索引字段上允许不区分大小写的搜索,它们只是不会使用索引,而且速度会像没有索引字段一样慢。

@重5由于这个问题被用来标记重复项,我想我可以澄清regex(不区分大小写的搜索需要)确实使用索引,但是它们必须进行完整的索引扫描。换句话说,他们不能有效地使用索引。幸运的是,该文件自2011年起已更新,但在此也值得注意。

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

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

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

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

小写字段可以是key:value对象存储,也可以只是带有前缀lc_u的字段名。我使用第二种方法来简化查询(深度对象查询有时会令人困惑)。

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

不错的解决方案,但幸运的是,从MongoDB3.4开始,就有对不区分大小写索引的本机支持。

使用Mongoose,这对我很有用:

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()是否是多余的?

是的。您不需要.toLowercase()。我已经把它从答案中去掉了。

嗯,这样行吗?当我搜索"mark"的时候,它也会得到每个带有"marko"的记录——有没有一种方法只忽略大小写敏感度?

找到了,正确的regex应该是:'^'+serach_name+'$','i'

这很危险。您没有转义用户名,因此可以注入任意regex。

假设您要搜索"table"中的"column",并且要进行大小写插入式搜索。最有效的方法如下:

//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"为选项设置的无实体条件进行搜索。

祝你一切顺利。

在使用基于regex的查询时,需要记住一件非常重要的事情——当您为登录系统执行此操作时,请转义正在搜索的每个字符,不要忘记^和$运算符。如果您已经在使用它,那么lodash有一个很好的功能:

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

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

在MongoDB 2.2中引入了聚合框架。可以使用字符串运算符"$strcasecmp"在字符串之间进行不区分大小写的比较。它比使用regex更推荐也更容易。

下面是聚合命令操作符的官方文档:https://docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/exp.u s诳strcasecmp。

如何在find()查询中使用它?查找(名称:$strcasecmp(名称))?

搜索并转义变量:

const escapeStringRegexp = require('escape-string-regexp')

const name = 'foo'

db.stuff.find({name: new RegExp('^' + escapeStringRegexp(name) + '$', 'i')})

转义变量可防止查询受到".*"或其他regex的攻击。

转义字符串regexp

这是唯一为我工作的。

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

下面的示例创建一个没有默认排序规则的集合,然后使用不区分大小写的排序规则在名称字段上添加索引。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 }, {collation: { locale: 'tr', strength: 2 } } )。

我为不区分大小写的regex创建了一个简单的func,我在过滤器中使用它。

private Func CaseInsensitiveCompare = (field) =>

BsonRegularExpression.Create(new Regex(field, RegexOptions.IgnoreCase));

然后您只需按如下所示对字段进行筛选。

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

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

string s ="searchTerm";

var filter = Builders.Filter.Where(p => p.Title.ToLower().Contains(s.ToLower()));

var listSorted = collection.Find(filter).ToList();

var list = collection.Find(filter).ToList();

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

这也避免了

var filter = Builders.Filter.Eq(p => p.Title.ToLower(), s.ToLower());

MongoDB会认为p.title.tolower()是一个属性,无法正确映射。

谢谢,这对我有用。这里我们需要在变量中获取过滤器,然后传入find()方法。

对于任何使用golang的用户,希望使用mongodb和mgo godoc globalsign库进行区分大小写的全文搜索。

collation := &mgo.Collation{

Locale:  "en",

Strength: 2,

}

err := collection.Find(query).Collation(collation)

使用ReGEXP,如果其他选项对您不起作用,那么regexp是一个很好的选项。它使字符串区分大小写。

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

username的值与/John/i的值相同。

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

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

正如您在Mongo Docs中看到的,从3.2版开始,$text索引默认情况下不区分大小写:https://docs.mongodb.com/manual/core/index text/text index case-insensitivity

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

在这种情况下,使用全文搜索是错误的(并且有潜在的危险),因为问题是关于进行不区分大小写的查询,例如,username: 'bill'匹配BILL或BILL,而不是全文搜索查询,后者也将匹配BILL的词干词,如EDOCX1。〔4〕、billed等。

这些已经过字符串搜索测试

{'_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

我也遇到过类似的问题,这对我很有帮助:

const flavorExists = await Flavors.findOne({

'flavor.name': { $regex: flavorName, $options: 'i' },

});

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

@Dandascalescu不知道你在说什么,在ctrl+f上,类似的解决方案在2018年9月发布了很多赞成票。我在2018年4月发布了我的答案。我把这个贴出来是因为当时没有。另外,在警告那些只想真正帮助别人的人之前,请先检查一下它是什么时候发布的。

我说的是2016年4月的答案,2016年5月的答案。两者都使用$regex和$options。你在ctrl+f中做了什么?

此外,使用$regex是低效的,而且可能不安全,正如我在2016年另一个答案的编辑中所解释的。如果答案不再为社区服务,那么删除它们就没有什么可耻的了!

注意到低效的$regex,非常感谢。i ctrl+f$选项。我们只有两个人,在我们的$regex代码中没有新的regexp,分别是2018年4月和2018年9月。我的答案中没有使用新的regexp。我忘记了我在新的regexp中遇到的具体问题,当我删除它时,这个问题得到了解决,而只是使用我发布的这个解决方案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值