MongoDB:是否可以做一个不区分大小写的查询?
例:
> db.stuff.save({"foo":"bar"}); > db.stuff.find({"foo":"bar"}).count(); 1 > db.stuff.find({"foo":"BAR"}).count(); 0
你可以使用正则expression式 。
在你的例子中,将是:
db.stuff.find( { foo: /^bar$/i } );
不过,我必须说,也许你可以在途中降低(或提高)价值,而不是每次find它时都要花费额外的成本。 显然,这不会适用于人们的名字等,但也许像标签一样的用例。
更新:
原来的答案现在已经过时了。 Mongodb现在支持高级全文search,具有许多function。
原文答案:
需要注意的是,使用正则expression式不区分大小写的方式进行search意味着mongodb无法按索引进行search,因此对大型数据集的查询可能需要很长时间。
即使是小数据集,效率也不高。 你的cpu命中率要比你的查询权证大得多,如果你想要达到规模,这可能会成为一个问题。
作为替代,您可以存储一个大写的副本和search。 例如,我有一个用户名有混合大小写的用户表,但是id是大写的用户名副本。 这确保了区分大小写的重复是不可能的(同时拥有“Foo”和“foo”),我可以通过id = username.toUpperCase()进行search以获得不区分大小写的用户名search。
如果你的字段很大,如消息体,重复数据可能不是一个好的select。 我相信在这种情况下使用像Apache Lucene这样的外部索引器是最好的select。
请记住,前面的例子:
db.stuff.find( { foo: /bar/i } );
会导致包含栏的每个条目与查询(bar1,barxyz,openbar)相匹配,这可能是非常危险的用户名searchauth函数…
您可能需要通过使用适当的正则expression式来使其仅匹配search词,如下所示:
db.stuff.find( { foo: /^bar$/i } );
有关正则expression式的语法帮助,请参阅http://www.regular-expressions.info/
如果您需要从一个variables创build正则expression式,这是一个更好的方法来做到这一点: 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 } );
这样做的好处是可以更具编程性,或者如果您重复使用它,可以提前编译来提高性能。
db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity
Mongo(当前版本2.0.0)不允许对索引字段进行不区分大小写的search – 请参阅其文档 。 对于非索引字段,其他答案中列出的正则expression式应该没问题。
从Mongodb 3.4开始,您应该使用不区分大小写的sorting规则索引。 这是对越来越大的数据集进行不区分大小写search的最快方法。 我个人通过电子邮件发送了一位创始人,请让这个工作,他做到了! (这是JIRA 5年的问题,许多人都要求这个function)。 这是如何工作的:
不区分大小写的索引是通过指定1或2的强度来进行sorting的。您可以创build一个不区分大小写的索引,如下所示:
db.myCollection.createIndex({city: 1}, {collation: {locale: "en", strength: 2}});
或者,您可以在创build数据库时默认为整个集合执行此操作:
db.createCollection("Cities",{collation: {locale: "en",strength:2}});
像这样使用它:
db.myCollection.find({city: "new york"}).collation({locale: "en", strength: 2});
这将返回“纽约”,“纽约”等。
或者,您可以使所有索引在默认情况下使用sorting规则,如下所示:
db.createCollection("cities",{collation:{locale: "en", strength: 2}});
这种方法的好处是提高了大数据集的效率和速度。
欲了解更多信息: https : //jira.mongodb.org/browse/SERVER-90,https : //docs.mongodb.com/manual/reference/collation/
最好的方法是使用你select的语言,当为你的对象创build一个模型包装器时,你的save()方法遍历你将要search的一组字段,这些字段也被索引; 那些字段集应该有小写的对应,然后用于search。
每次对象再次保存时,小写属性将被检查并随主要属性的更改而更新。 这样做可以让你有效地search,但隐藏每次更新lc字段所需的额外工作。
小写字段可以是一个键:值对象存储或者只是带有前缀lc_的字段名称。 我使用第二个来简化查询(有时,深层对象查询可能会造成混淆)。
注意:您要为lc_字段build立索引,而不是基于它们的主要字段。
TL; DR
正确的方式在mongo中做到这一点
不要使用RegExp
自然而然地使用mongodb的内置索引,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步 :
需要在要search的任何文本字段上创build索引,而不进行索引查询将会非常慢
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
使用mongoose这工作对我来说:
var find = function(username, next){ User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){ if(err) throw err; next(null, res); }); }
在使用基于正则expression式的查询时要记住一件非常重要的事情 – 当您为login系统执行此操作时,请转义您正在search的每个字符 ,并且不要忘记^和$运算符。 Lodash有一个很好的function ,如果你已经使用它:
db.stuff.find({$regex: new RegExp(_.escapeRegExp(bar), $options: 'i'})
为什么? 设想一个用户input.*
作为他的用户名。 这将匹配所有用户名,通过猜测任何用户的密码启用login。
假设你想search“表”中的“列”,你想不区分大小写的search。 最好的和有效的方式如下:
//create empty JSON Object mycolumn = {}; //check if column has valid value if(column) { mycolumn.column = {$regex: new RegExp(column), $options: "i"}; } Table.find(mycolumn);
以上代码只是将您的search值添加为RegEx,并使用以“i”设置的不敏感标准作为选项进行search。
祝一切顺利。
在MongoDB 2.2中引入了聚合框架。 您可以使用string运算符“$ strcasecmp”在string之间进行不区分大小写的比较。 这比使用正则expression式更推荐和容易。
以下是关于汇总命令操作符的官方文档: https : //docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/#exp._S_strcasecmp 。
我为不区分大小写的正则expression式创build了一个简单的Func,我在filter中使用它。
private Func<string, BsonRegularExpression> CaseInsensitiveCompare = (field) => BsonRegularExpression.Create(new Regex(field, RegexOptions.IgnoreCase));
然后,您只需按如下方式筛选字段。
db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();
正如你可以在mongo文档中看到的那样 – 从版本3.2开始, $text
索引默认情况下不区分大小写: https : //docs.mongodb.com/manual/core/index-text/#text-index-case-insensitivity
创build一个文本索引,并在查询中使用$ text运算符 。
这些已经过testing的stringsearch
{'_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
在C#中使用filter适用于我。
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();
它甚至可能使用索引,因为我相信在返回之后调用方法,但是我还没有testing过。
这也避免了一个问题
var filter = Builders<Model>.Filter.Eq(p => p.Title.ToLower(), s.ToLower());
那个mongodb会认为p.Title.ToLower()是一个属性,不会正确映射。