javamongo忽略⼤⼩写,MongoDB:是否可以进⾏不区分⼤⼩
写的查询?
例⼦:
> db.stuff.save({"foo":"bar"});
> db.stuff.find({"foo":"bar"}).count();
1
> db.stuff.find({"foo":"BAR"}).count();
由于MongoDB 3.2,您可以使⽤$caseSensitive: false执⾏不区分⼤⼩写的搜索。参见:
请注意,这只在⽂本索引上。
@马丁:默认情况下,$caseSensitive已经是假的了,这并不能回答这个问题,因为它只在索引字段上⼯作。OP正在寻不区分⼤⼩写的字符串⽐较。
你可以⽤正则表达式。
在您的⽰例中:
db.stuff.find( { foo: /^bar$/i } );
不过,我必须说,也许你可以在进⼊的过程中降低(或提⾼)价值,⽽不是每次你发现它都要承担额外的成本。很明显,这对⼈名之类的⼈不起作⽤,但也可能是像标签这样的⽤例。
这很管⽤。让它在php中使⽤:$collection->find(array('key'=>new mongoregex('/'$val.'/i'));
尤其是当你在插⼊⼀个字符串(foo/x/i),其中可能有问号。
别忘了加上preg_引号()。
别忘了^和$:MongoRegex('/^'。普雷格报价($val)。美元/我)
时间正则表达式java请注意,这将执⾏完全扫描,⽽不是使⽤索引。
如果他⼀开始就使⽤锚定,就不会进⾏全⾯扫描,因此朱利安的建议很重要。
嘿,我跟着朱利安。但是,⽆法得到结果。之后,我跟着卢克·丹尼斯。我得到了结果。请给我建议。哪⼀个在技术上是正确的?
这对我有⽤,谢谢。是的,预售/预售是⼀个很好的建议。
我必须做:array("key"=>array("$regex"=>new mongoregex("/^")。⽡尔。$/i));
我看不出这根绳⼦的上下套管有多⼤帮助。如果数据库中的值为"foo",并且您正在搜索"foo"或"foo",则两者都不匹配。它不像传统的SQL那样,在变量中有db字段,并且可以将搜索字符串和db字符串都⼩写。我是否遗漏了⼀些明显的东西?
它们的意思是将存储在数据库上的值⼩写("foo"⽽不是"foo")—⽽不是查询。这可能需要在⽂档中添加⼀个特殊的"search"值:"myvalue":"foo","searchable":"foo"
如果试图检查包含regex相关字符的字符串,则此⽅法不起作⽤。例如问号或星号。
@你可以像往常⼀样简单地避开那些⾓⾊。/this\/has\/slashes\//
"对于不区分⼤⼩写的正则表达式查询,这些查询通常不能有效地使⽤索引。"-
&db/manual/reference/operator/query/regex
regex可以⼯作,但它们会应⽤regex扫描整个数据库,⽽不使⽤索引。什么是很有感情的
从MongoDB3.4开始,有⼀个更快更合适的解决⽅案:不区分⼤⼩写的索引。还有@pax,这是不正确的。请参阅SEBPIQ发布的参考资料。
更新:
原来的答案现在已经过时了。MongoDB现在⽀持⾼级全⽂搜索,具有许多功能。
原始答案:
需要注意的是,使⽤regex的不区分⼤⼩写/i进⾏搜索意味着MongoDB⽆法按索引进⾏搜索,因此针对⼤型数据集的查询可能需要很长时间。
即使是⼩数据集,它也不是很有效。您的CPU命中率远远⾼于查询要求,如果您试图实现规模,这可能会成为⼀个问题。
作为⼀种替代⽅法,您可以存储⼀个⼤写的副本并对其进⾏搜索。例如,我有⼀个⽤户表,它有⼀个混合⼤⼩写的⽤户名,但ID是⽤户名的⼤写副本。这确保了不可能进⾏区分⼤⼩写的复制(不允许同时使⽤"foo"和"foo"),并且我可以通过uppercase()进⾏搜索,以获得对username不区分⼤⼩写的搜索。
如果您的字段很⼤,例如消息体,那么复制数据可能不是⼀个好的选择。我相信在这种情况下,使⽤像ApacheLucene这样的⽆关索引器是最好的选择。
有没有显⽰索引如何⼯作的⽂档?我问是因为,如果我记得的话,MarkLogic能够保存⼀个额外的不区分⼤⼩写的索引…也许蒙古⼈也这么做?
Raymo,⼀个不区分⼤⼩写的索引特性,在蒙古⼈中并不存在,但它正在被讨论中。/browse/server-90
@dan,最新mongodb中的信息是,"如果存在字段的索引,那么mongodb将正则表达式与索引中的值进⾏匹配,这⽐集合扫描更快。"--/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 } );
这个答案看起来像是⼀个评论。
然后您可以执⾏以下操作:
var string ="SomeStringToFind";
var regex = new RegExp(["^", string,"$"].join(""),"i");
// Creates a regex of: /^SomeStringToFind$/i
db.stuff.find( { foo: regex } );
这样做的好处是更具编程性,或者如果您经常重⽤它,可以通过提前编译来提⾼性能。
new RegExp("^" + oLowerCase(),"i")也很好⽤
如果变量来⾃请求:stackoverflow/a/50633536/5195127,则应考虑转义字符串以提⾼安全性。
从MongoDB 3.4开始,本机⽀持不区分⼤⼩写的索引
从MongoDB开始,执⾏快速不区分⼤⼩写搜索的推荐⽅法是使⽤不区分⼤⼩写的索引。
我亲⾃给其中⼀位创始⼈发了邮件,希望他能成功完成这项⼯作!⾃2009年以来,这是⼀个关于JIRA的问题,许多⼈都要求使⽤该功能。⼯作原理如下:
通过指定强度为1或2的排序规则来创建不区分⼤⼩写的索引。您可以这样创建不区分⼤⼩写的索引:
ateIndex(
{ city: 1 },
{
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:
需要在要搜索的任何⽂本字段上创建索引,⽽不创建索引查询将⾮常慢。
ateIndex( { 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年起已更新,但在此也值得注意。
dbpany_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) {
}
Table.find(mycolumn);
上⾯的代码只是将您的搜索值添加为regex,并使⽤以"i"为选项设置的⽆实体条件进⾏搜索。
祝你⼀切顺利。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论