注意
本页介绍用于自管理(非 Atlas)部署的正则表达式搜索功能。对于托管在 MongoDB Atlas 上的数据,MongoDB 提供了一种改进的全文搜索解决方案,即 Atlas Search,它有自己的 $regex 运算符。要了解更多信息,请参阅 Atlas Search 文档中的 $regex。
定义
兼容性
可以使用 $regex 查找托管在以下环境中的部署:
MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
使用以下语法变体之一:
{ <field>: { $regex: /pattern/, $options: '<options>' } } { "<field>": { "$regex": "pattern", "$options": "<options>" } } { <field>: { $regex: /pattern/<options> } }
注意
要将$regex 与mongodump 一起使用,请用单引号 ('{... }') 将查询文档括起来,以确保它不会与Shell交互。
查询文档必须采用扩展 JSON v2 格式(宽松模式或规范/严格模式),其中包括用引号将字段名称和操作符包围起来。例如:
mongodump -d=sample_mflix -c=movies -q='{"year": {"$regex": "20"}}'
您还可以使用正则表达式对象 (/pattern/) 来指定正则表达式:
{ <field>: /pattern/<options> }
有关语法使用的限制,请参阅 $regex 与 / 模式/ 事务语法。
以下 <options> 可用于正则表达式:
选项 | 说明 |
|---|---|
| 不区分大小写,以匹配大小写。 有关示例,请参阅执行不区分大小写的正则表达式匹配。 |
| |
| “扩展”功能,可忽略 此外,其还会忽略未转义的哈希/磅 (
|
| 允许点字符 () |
| Unicode 选项,已接受但多余。默认下,为 |
注意
$regex 不支持全局搜索修饰符 g。
行为
$regex 与 /pattern/ Syntax
$in 表达式
要在 $in 查询谓词操作符中包含正则表达式,您可以仅使用 JavaScript 正则表达式对象(/pattern/)。
例如:
{ name: { $in: [ /^acme/i, /^ack/ ] } }
您无法在 $in 操作符内使用 $regex 操作符表达式。
字段的隐式 AND 条件
要在以逗号分隔的字段查询条件列表中包含正则表达式,请使用 $regex 操作符。例如:
{ name: { $regex: /acme.*corp/i, $nin: [ 'acmeblahcorp' ] } } { name: { $regex: /acme.*corp/, $options: 'i', $nin: [ 'acmeblahcorp' ] } } { name: { $regex: 'acme.*corp', $options: 'i', $nin: [ 'acmeblahcorp' ] } }
x 和 s 选项
要使用 x 选项或 s 选项,必须使用 $regex 操作符表达式和 $options 操作符。例如,要指定 i 和 s 选项,您必须同时使用 $options:
{ name: { $regex: /acme.*corp/, $options: "si" } } { name: { $regex: 'acme.*corp', $options: "si" } }
PCRE 与 JavaScript
要在正则表达式中使用JavaScript不支持的 PCRE 支持的功能,请使用$regex 操作符并将模式指定为字符串。
要匹配不区分大小写的字符串:
"(?i)"开始不区分大小写的匹配。"(?-i)"结束不区分大小写的匹配。
例如,正则表达式 "(?i)a(?-i)cme" 会匹配符合以下条件的字符串:
以
"a"或"A"开头。这是不区分大小写的匹配。以
"cme"结尾。这是区分大小写的匹配。
这些字符串与示例正则表达式匹配:
"acme""Acme"
以下示例使用 $regex 操作符查找与正则表达式 "(?i)a(?-i)cme" 匹配的 name 字段字符串:
{ name: { $regex: "(?i)a(?-i)cme" } }
从版本 6.1 开始,MongoDB 使用 PCRE2(Perl 兼容正则表达式)库来实现正则表达式模式匹配。要了解有关 PCRE2 的更多信息,请参阅 PCRE 文档。
$regex 和 $not
$not操作符可以对以下两者执行逻辑NOT 操作:
正则表达式对象 (
/pattern/)例如:
db.inventory.find( { item: { $not: /^p.*/ } } ) $regex操作符表达式例如:
db.inventory.find( { item: { $not: { $regex: "^p.*" } } } ) db.inventory.find( { item: { $not: { $regex: /^p.*/ } } } )
索引使用
$regex 查询的索引使用和性能取决于查询是区分大小写还是不区分大小写。
区分大小写的查询
对于区分大小写的正则表达式查询,如果索引存在字段,则MongoDB将正则表达式与索引中的值进行匹配。这可能比集合扫描更快。
如果正则表达式是“前缀表达式”,则可以进行进一步优化,这意味着所有潜在的匹配项都以同一字符串开头。这允许MongoDB从该前缀构造一个“范围”,并且只匹配指定范围内索引的值。
如果正则表达式以插入符号 (^) 或左锚点 (\A) 开头,后跟一串简单的符号,则该正则表达式是“前缀表达式”。示例,正则表达式 /^abc.*/ 经过优化,仅匹配索引中以 abc 开头的值。
此外,尽管 /^a/、/^a.*/ 和 /^a.*$/ 匹配等效字符串,但它们具有不同的性能特征。如果存在适当的索引,则所有这些表达式都会使用索引。但是,/^a.*/ 和 /^a.*$/ 的速度较慢。 /^a/ 可以在匹配前缀后停止扫描。
不区分大小写的查询
不区分大小写的索引不会提升 $regex 查询的性能,因为 $regex 操作符不支持排序规则,因此无法利用此类索引。
示例
本部分中的示例使用以下 products 集合:
db.products.insertMany( [ { _id: 100, sku: "abc123", description: "Single line description." }, { _id: 101, sku: "abc789", description: "First line\nSecond line" }, { _id: 102, sku: "xyz456", description: "Many spaces before line" }, { _id: 103, sku: "xyz789", description: "Multiple\nline description" }, { _id: 104, sku: "Abc789", description: "SKU starts with A" } ] )
执行 LIKE 匹配
下面的示例匹配 sku 字段与 "%789" 相似的所有文档:
db.products.find( { sku: { $regex: /789$/ } } )
该示例类似于以下SQL LIKE声明:
SELECT * FROM products WHERE sku like "%789";
示例输出:
[ { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 103, sku: 'xyz789', description: 'Multiple\nline description' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
执行不区分大小写的正则表达式匹配
以下示例使用 i 选项对以 ABC 开头的 sku 值执行不区分大小写的匹配:
db.products.find( { sku: { $regex: /^ABC/i } } )
示例输出:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
仅匹配整个单词
使用 \b 单词边界锚点仅匹配整个单词。单词边界匹配单词字符和非单词字符之间的位置,或者字符串的开头或结尾的位置。
以下示例匹配 description字段包含单词 line 作为完整单词但不是另一个单词(如 multiline)的一部分的文档:
db.products.find( { description: { $regex: /\bline\b/ } } )
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 102, sku: 'xyz456', description: 'Many spaces before line' } ]
MongoDB不会返回包含 _id: 103 的文档,因为其 description字段包含的 line 仅作为单词 Multiple\nline 的一部分。 \n(换行符)充当第二次出现的单词边界。
注意
有关使用 UTF-8 字符匹配单词边界,请参阅扩展正则表达式选项以匹配 ASCII 之外的字符。
以指定模式开头的行的多行匹配
以下示例使用 m 选项为多行字符串匹配以字母 S 开头的行:
db.products.find( { description: { $regex: /^S/, $options: 'm' } } )
示例输出:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
如果没有 m 选项,示例输出为:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
如果 $regex模式不包含锚点,则该模式将匹配整个字符串。示例:
db.products.find( { description: { $regex: /S/ } } )
示例输出:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
使用 . 点字符匹配新行
以下示例使用s 选项允许点字符 (). 匹配包括换行符在内的所有字符,并使用i 选项执行不区分大小写的匹配:
db.products.find( { description: { $regex: /m.*line/, $options: 'si' } } )
示例输出:
[ { _id: 102, sku: 'xyz456', description: 'Many spaces before line' }, { _id: 103, sku: 'xyz789', description: 'Multiple\nline description' } ]
如果没有 s 选项,查询将返回:
[ { _id: 102, sku: 'xyz456', description: 'Many spaces before line' } ]
忽略模式中的空格
以下示例使用 x 选项忽略空格和注释,在匹配模式中由 # 表示并以 \n 结尾:
var pattern = "abc #category code\n123 #item number" db.products.find( { sku: { $regex: pattern, $options: "x" } } )
示例输出:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' } ]
使用正则表达式匹配字符串中的大小写
以下示例使用正则表达式 "(?i)a(?-i)bc" 匹配包含以下内容的 sku 字段字符串:
"abc""Abc"
db.products.find( { sku: { $regex: "(?i)a(?-i)bc" } } )
示例输出:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
扩展正则表达式选项以匹配 ASCII 之外的字符
6.1 版本新增内容。
默认下,某些正则表达式选项(例如 /b 和 /w)仅识别 ASCII 字符。在对 UTF-8 字符执行正则表达式匹配时,这可能会导致意外结果。
从 MongoDB 6.1 开始,您可以指定 *UCP 正则表达式选项来匹配 UTF-8 字符。
重要
UCP 选项的性能
与未指定 *UCP 选项的查询相比,指定该选项会导致查询变慢,因为 *UCP 需要多级表查找来执行匹配。
例如,考虑 songs 集合中的以下文档:
db.songs.insertMany( [ { _id: 0, "artist" : "Blue Öyster Cult", "title": "The Reaper" }, { _id: 1, "artist": "Blue Öyster Cult", "title": "Godzilla" }, { _id: 2, "artist" : "Blue Oyster Cult", "title": "Take Me Away" } ] )
以下正则表达式查询在正则表达式匹配中使用 \b 选项。\b 选项与单词边界匹配。
db.songs.find( { artist: { $regex: /\byster/ } } )
示例输出:
[ { _id: 0, artist: 'Blue Öyster Cult', title: 'The Reaper' }, { _id: 1, artist: 'Blue Öyster Cult', title: 'Godzilla' } ]
先前的结果出乎意料,因为返回的 artist 字段中没有一个全词以匹配的字符串 (yster) 开头。执行匹配时,文档 _id: 0 和 _id: 1 中的 Ö 字符将被忽略,因为 Ö 是 UTF-8 字符。
预期结果是查询不会返回任何文档。
要允许查询识别 UTF-8 字符,请在模式前指定 *UCP 选项:
db.songs.find( { artist: { $regex: "(*UCP)/\byster/" } } )
上一个查询没有返回任何文档,这是预期的结果,因为 artist 字段中没有一个完整单词以字符串 yster 开头。
提示
正则表达式模式的转义字符
指定 *UCP 或任何其他正则表达式选项时,请为您的Shell或驾驶员使用正确的转义字符。