Docs 菜单

Docs 主页开发应用程序MongoDB Manual

$regex

在此页面上

  • 定义
  • 兼容性
  • 语法
  • 行为
  • 举例

注意

本页介绍适用于自托管(非 Atlas)部署的正则表达式搜索功能。对于 MongoDB Atlas 上托管的数据,MongoDB 提供了改进的全文搜索解决方案 Atlas Search ,它有自己的 $regex操作符。要了解更多信息,请参阅 Atlas Search 文档中的$regex

$regex

为查询中的模式匹配字符串提供正则表达式功能。

可以使用 $regex 查找托管在以下环境中的部署:

  • MongoDB Atlas :用于在云中部署 MongoDB 的完全托管服务

要使用 $regex,请使用以下事务语法:

{ <field>: { $regex: /pattern/, $options: '<options>' } }
{ "<field>": { "$regex": "pattern", "$options": "<options>" } }
{ <field>: { $regex: /pattern/<options> } }

注意

要将$regexmongodump一起使用,必须用单引号 ('{ ... }') 将查询文档括起来,以确保它不会与 shell 环境交互。

查询文档必须采用扩展 JSON v2 格式(宽松模式或规范/严格模式),其中包括用引号将字段名称和操作符包围起来。例如:

mongodump -d=sample_mflix -c=movies -q='{"year": {"$regex": "20"}}'

在 MongoDB 中,您还可以使用正则表达式对象(即 /pattern/)指定正则表达式:

{ <field>: /pattern/<options> }

有关特定语法使用的限制,请参阅$regex 与 /pattern/ 语法。

$options

以下 <options> 可用于正则表达式。

选项
说明
i
不区分大小写,以匹配大小写。有关示例,请参阅执行不区分大小写的正则表达式匹配。
m

对于包含锚点的模式(即, ^表示开始, $表示结束),在每行的开头或结尾匹配具有多行值的字符串。如果没有此选项,这些锚点将在字符串的开头或结尾匹配。有关示例,请参阅以指定模式开头的行的多行匹配。

如果模式不包含锚点,或者字符串值没有换行符(如 \n),则 m 选项没有任何作用。

x

“扩展”功能,可忽略 $regex 模式中的所有空白字符,除非转义或包含在字符类中。

此外,其还会忽略未转义的哈希/磅 (#) 字符和下一新行(含)之间的字符,因此您可以在复杂的模式中加入注释。这种情况只适用于数据字符;空白字符绝不能出现在模式中的特殊字符序列中。

x 选项不影响对 VT 字符的处理(如代码 11)。

s
允许点字符(即. )匹配包括换行符在内的所有字符。有关示例,请参阅使用.点字符匹配新行。
u
支持 Unicode。此标志已被接受,但是多余的。默认情况下, $regex操作符中设置 UTF,因此无需u选项。

注意

$regex操作符支持全局搜索修饰符g

要在 $in 查询表达式中包含正则表达式,您可以仅使用 JavaScript 正则表达式对象(即/pattern/)。例如:

{ name: { $in: [ /^acme/i, /^ack/ ] } }

无法$in 操作符内使用 $regex 操作符表达式。

要在以逗号分隔的字段查询条件列表中包含正则表达式,请使用 $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选项,必须将$regex操作符表达式$options操作符一起使用。例如,要指定is选项,必须对二者使用$options

{ name: { $regex: /acme.*corp/, $options: "si" } }
{ name: { $regex: 'acme.*corp', $options: "si" } }

要在正则表达式中使用 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 文档。

$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" }
] )

下面的示例匹配 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 选项对 sku 值以 ABC 开头的文档执行不区分大小写的匹配。

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' }
]

以下示例使用 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' }
]

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/" } } )

上一个查询未返回任何文档,这是预期的结果。

提示

正则表达式模式的转义字符

指定 *UCP 或任何其他正则表达式选项时,确保为 shell 或驱动程序使用正确的转义字符。

← $mod
$text →