366

例子:

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

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

25 回答 25

410

您可以使用正则表达式

在您的示例中,这将是:

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

不过,我必须说,也许您可​​以在途中降低(或提高)价值,而不是每次找到它时都会产生额外的成本。显然,这不适用于人名等,但可能适用于标签等用例。

于 2009-12-07T22:46:04.453 回答
206

更新:

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

原始答案:

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

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

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

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

于 2010-12-14T16:22:33.990 回答
117

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

我亲自向其中一位创始人发送了电子邮件,请让这项工作正常进行,他做到了!自 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 }
);

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

其他注意事项

  • 在这种情况下,建议使用全文搜索的答案是错误的(并且有潜在危险)。问题是关于进行不区分大小写的查询,例如username: 'bill'匹配BILLor Bill,而不是全文搜索查询,这也将匹配的词干bill,例如Billsbilled

  • 建议使用正则表达式的答案很慢,因为即使使用索引,文档也指出

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

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

于 2016-12-01T15:47:36.153 回答
84

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

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

于 2012-07-12T20:39:23.303 回答
70

请记住前面的示例:

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

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

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

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

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

于 2011-06-03T08:59:39.433 回答
31
db.company_profile.find({ "companyName" : { "$regex" : "Nilesh" , "$options" : "i"}});
于 2018-09-04T14:37:22.617 回答
21
db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity
于 2015-12-17T12:57:31.933 回答
20

TL;博士

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

不要使用正则表达式

去自然并使用 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


 
于 2016-08-27T19:29:25.000 回答
9

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

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

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

于 2016-05-06T09:01:42.033 回答
8

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

于 2011-10-24T19:31:14.427 回答
8

假设您要在“表格”中搜索“列”并且您想要不区分大小写的搜索。最好和最有效的方法是:

//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”作为选项设置的不敏感条件进行搜索。

于 2016-04-30T14:44:28.013 回答
8

用于搜索变量并将其转义:

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

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

转义字符串正则表达式

于 2018-05-31T22:14:27.243 回答
6

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

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

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

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

于 2011-04-20T17:30:05.890 回答
6

使用猫鼬这对我有用:

var find = function(username, next){
    User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){
        if(err) throw err;
        next(null, res);
    });
}
于 2014-10-16T04:54:52.343 回答
5

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

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

于 2017-05-20T04:20:54.687 回答
4

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

下面的示例创建一个没有默认排序规则的集合,然后使用不区分大小写的排序规则在名称字段上添加索引。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
于 2017-11-22T16:19:44.880 回答
3

我很惊讶没有人通过使用/^bar$/iif bar是密码或帐户 ID 搜索来警告正则表达式注入的风险。( bar => .*@myhackeddomain.com例如,我敢打赌:使用\Q \E正则表达式特殊字符!在 PERL 中提供

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

您应该转义bar变量\字符\\以避免\E再次利用,例如bar = '\E.*@myhackeddomain.com\Q'

另一种选择是使用正则表达式转义字符策略,如此处描述的Javascript 等效于 Perl 的 \Q ... \E 或 quotemeta()

于 2020-10-18T08:43:28.213 回答
2

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

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

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

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

于 2018-07-03T05:06:39.853 回答
2

如果您使用的是 MongoDB Compass:

转到集合,在过滤器类型中 -> {Fieldname: /string/i}

对于使用 Mongoose 的 Node.js:

Model.find({FieldName: {$regex: "stringToSearch", $options: "i"}})

于 2021-10-20T04:06:04.230 回答
1

在 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() 是一个属性,不会正确映射。

于 2017-08-07T17:09:42.223 回答
1

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

  const flavorExists = await Flavors.findOne({
    'flavor.name': { $regex: flavorName, $options: 'i' },
  });
于 2018-04-11T07:36:04.663 回答
0

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

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

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

db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();
于 2015-09-05T23:18:28.150 回答
0

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

{'_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
于 2017-05-12T14:42:36.947 回答
0

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

collation := &mgo.Collation{
    Locale:   "en",
    Strength: 2, 
}


err := collection.Find(query).Collation(collation)
于 2018-12-13T14:13:58.167 回答
-1

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

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

于 2017-05-10T15:40:50.480 回答