检查字段是否包含字符串

735
我正在寻找一个运算符,它可以让我检查字段的值是否包含某个字符串。
类似于:
```if (fieldValue contains 'certainString') { // do something }```
请注意,这只是一个示例,可能不起作用。
db.users.findOne({$contains:{"username":"son"}})

这是否可能?

17个回答

1126

你可以用以下代码实现。

db.users.findOne({"username" : {$regex : "son"}});

27
请注意,这将不会有效利用索引,并导致扫描所有值以寻找匹配项。请参见有关正则表达式的注意事项。 - Stennie
12
@Stennie,那么你建议如何有效利用索引和查找子字符串? - Blue Sky
5
如果您的常见用例是对字段进行自由文本搜索,并且您有大量文档,我建议对文本进行分词以实现更高效的查询。您可以使用multikeys进行简单的全文搜索,或者构建一个独立的倒排索引集合。对于不频繁的搜索或小型文档集合,扫描完整索引可能具有可接受(虽然不是最佳)的性能。 - Stennie
3
建议查看Mongo 2.6中的全文搜索功能。 - wprl
1
@mjwrazor 最简单的确认索引使用的方法是解释您的查询。我还建议您发布一个新问题,详细说明您的用例,而不是在这里讨论评论;-)。 - Stennie
显示剩余4条评论

266

1
所选答案对我没有用,但这个有用(我正在通过docker exec命令执行mongo查询)。我认为这个应该是被选中的答案,因为它似乎更加通用。 - Arthur Weborg
6
我会尽力做到最好!以下是翻译的结果:像所选答案中的评论一样,我认为 db.users.findOne({"username" : /.*son.*/}); 可能也过于复杂了,正则表达式可以简单地写成 /son/ - Arthur Weborg
2
比使用 $regex 更简洁的方法 - Lionet Chen
8
将其编辑为仅使用{ username: /son/ } - Wyck
4
如果“儿子”这个词是可变的,就像我猜想的大多数用例一样。 - Amr Alaa

226

56
删除所有查询还是修改它?大多数人都知道 SQL,这对于理解 MongoDB 有帮助。 - Zheng Kai
140
@maerics,我个人认为郑的MySQL相关内容很有用,因为它提供了一个参考点。 - Mike Bartlett
77
我也觉得SQL参考资料相关,我认为应该保留。 - vikingsteve
3
确实。这个 SQL 示例只有两行文字。一些人可能更喜欢忽略它,而另一些人可能会从中受益。对于第一组人来说,忽略它的代价可能远远超过了第二组人从中受益的好处。 - phoog
请注意,SQL的LIKE不支持正则表达式。在MySQL中,相当于REGEXP或RLIKE。 - Slaven Rezic
1
@zhengKai 如果你想查询像“Son”这样的用户名和其他值,是否可以有多个条件呢?例如:db.users.find({username:/Son/,/Dad/,/Mom/}) 可以检索所有包含“Son, dad, mom”等的用户名。 - JayC

107

从2.4版本开始,您可以在要搜索的字段上创建文本索引并使用$text运算符进行查询。

首先,创建索引:

db.users.createIndex( { "username": "text" } )

然后,进行搜索:

db.users.find( { $text: { $search: "son" } } )

基准测试(约150K个文档):

  • 正则表达式(其他答案)=> 5.6-6.9秒
  • 文本搜索 => .164-.201秒

注:

  • 一个集合只能有一个文本索引。如果您想搜索任何字符串字段,可以使用通配符文本索引,如下所示:
 db.collection.createIndex( { "$**": "text" } )
  • 文本索引可能很大。它为每个插入的文档中每个索引字段中的每个唯一词干后的单词包含一个索引条目。
  • 建立文本索引所需的时间比普通索引更长。
  • 文本索引不存储短语或有关文档中单词接近程度的信息。因此,当整个集合适合RAM时,短语查询将运行得更有效。

27
实际上,文本操作符不支持执行“包含”操作,因此它只会返回完全匹配的单词。目前3.0版本唯一的选择是使用正则表达式,例如:db.users.find({ username:/son/i }),这将查找所有包含“son”的用户(不区分大小写)。 - comeGetSome
3
在向/从集合中添加或删除文档时,您是否需要重新索引? - Jake Wilson
问题的标题是“包含”。全文搜索不适用于该问题。 - Daniel Viglione
1
@comeGetSome 你说得对。有关于如何以快速有效的方式完成这个任务的更新吗? - Alex Totolici

59

由于这是搜索引擎中排名靠前的结果之一,而且以上方法似乎都不适用于MongoDB 3.x版本,因此这里提供一个可行的正则表达式搜索方法:

db.users.find( { 'name' : { '$regex' : yourvalue, '$options' : 'i' } } )

无需创建额外的索引或类似物。

2
正则表达式需要进行清理。 - sean
2
来自谷歌,这是唯一适用于我的选项。从文档中可以看出,选项i是为了“不区分大小写匹配大写和小写字母”。 - Matt
2022年,这是正确的答案。因为如果我使用$regaxe而不是'$regex',Pylance会报错。 - Alisher
嘿@Nitai,我有一个问题,我想在正则表达式中给出2个值。我的意思是,字符串要么与value1匹配,要么与value2匹配。我该如何修改这个查询? - Bug
@Nitai 上述方法无法在 URL 搜索 google.com/test/test_page 中正常工作。 - Apurv Chaudhary

22

如果您要通过Python连接MongoDB,这就是您需要做的:

db.users.find({"username": {'$regex' : '.*' + 'Son' + '.*'}})

您也可以使用变量名代替'Son',从而进行字符串拼接。


上述查询在$match操作符下与URL不起作用,例如: “details.uri”:{ “$regex”:“.*phubprod.princeton.edu/psp/phubprod.*”, “$options”:“i” } - Apurv Chaudhary

21

完成此任务的最简单方法

如果您希望查询区分大小写

db.getCollection("users").find({'username':/Son/})

如果您希望查询是不区分大小写

db.getCollection("users").find({'username':/Son/i})

1
如何在正则表达式中使用变量? - Hisham
@Hisham 这实际上是正则表达式(请注意,字符串中使用的是 / 符号而不是 '")。 - loicnestler
@Hisham 你可以直接使用 new RegExp(variable) 的正则表达式类。 - Anthony

12

理想答案是使用索引i选项进行不区分大小写的匹配

db.users.findOne({"username" : new RegExp(search_value, 'i') });

2
正则表达式需要进行清理。 - sean

12

11

我使用这段代码,可以用于搜索子字符串。

db.users.find({key: { $regex: new RegExp(value, 'i')}})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接