文档菜单
文档首页
/
MongoDB 手册
/ / / /

$regex

本页内容

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

注意

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

$regex

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

您可以在以下环境中使用 $regex

  • MongoDB Atlas:云中MongoDB部署的全托管服务

  • MongoDB Enterprise:基于订阅、自行管理的MongoDB版本

  • MongoDB Community:源代码可获取、免费使用且自行管理的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。此标志被接受,但多余。UTF 在 $regex 操作符中默认设置,使得 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" } }

使用PCRE 支持的正则表达式功能,而这些功能在 JavaScript 中不受支持,您必须使用 $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 从该前缀构造一个“范围”并仅匹配索引中位于该范围内的值。

正则表达式如果以一个 caret(^)或一个左锚点(\A)开头,后跟一串简单符号,则称为“前缀表达式”。例如,正则表达式 /^abc.*/ 将通过只匹配以 abc 开头的索引值来优化。

此外,虽然 /^a//^a.*//^a.*$/ 匹配等效的字符串,但它们的性能特征不同。所有这些表达式如果存在适当的索引,则都会使用索引;然而,/^a.*//^a.*$/ 的速度较慢。/^a/ 可以在匹配前缀后停止扫描。

不区分大小写的索引通常不会提高 $regex 查询的性能。《code class="leafygreen-ui-1l06pbn">$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选项对以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' }
]

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