MongoDB 正则表达式 ($regex) 及示例

⚡ 智能摘要

MongoDB 正则表达式使用 $regex 运算符、$options 标志(用于区分大小写)、锚点(用于精确匹配)和斜杠分隔符(用于在字段值未知时进行精确匹配)来执行模式匹配,从而在文档中查找字符串。

  • 🔍 $正则表达式 OperaTOR: db.collection.find({field:{$regex:”pattern”}}) 匹配包含该模式的文档。
  • 🎯 Anchors: ^ 和 $ 强制精确匹配,将模式绑定到字符串的开头和结尾。
  • 🔠 不区分大小写: $options 'i' 标志匹配文本,无论大小写。
  • 斜杠分隔符: 饺子皮ping /…/ 中的模式无需编写 $regex 运算符即可匹配。
  • 📉 最后 N 个文档: 将 sort({_id:-1}) 与 limit(n) 结合使用,以返回最新记录。
  • 🤖 人工智能辅助: 助手会构建正则表达式模式并标记全集扫描的性能成本。

MongoDB 正则表达式(Regex)

正则表达式用于模式匹配,其主要目的是在文档中查找字符串。

有时在检索集合中的文档时,您可能不知道要搜索的确切字段值。因此,可以使用正则表达式来帮助根据模式匹配搜索值检索数据。

使用 $regex 运算符进行模式匹配

$regex 运算符 MongoDB 用于在集合中搜索特定字符串。以下示例显示了如何执行此操作。

假设我们有一个包含“Employeeid”和“EmployeeName”字段的Employee集合。同时假设我们的集合中包含以下文档。

员工ID 员工姓名
22 纽马丁
2 Mohan
3 Joe
4 莫汉
100 Guru99
6 古朗

下面的代码中使用了 $regex 运算符来指定搜索条件。

使用 $regex Opera模式匹配

db.Employee.find({EmployeeName : {$regex: "Gu" }}).forEach(printjson)

Code 说明:

  1. 这里我们要查找所有姓名中包含字符“Gu”的员工。因此,我们使用 $regex 运算符来定义搜索条件“Gu”。
  2. printjson 用于以更好的方式打印查询返回的每个文档。

如果命令执行成功,将显示以下输出:

输出:

使用 $regex Opera模式匹配

输出清楚地显示,返回了员工姓名包含“Gu”字符的那些文档。

假设您的文档库中包含以下文档,以及一份包含员工姓名的附加文档,该员工姓名为“Guru999”。如果您输入的搜索条件是“Guru99”,它还会返回包含“Guru999”。但假设我们不需要这个,而只想返回包含“Guru99”。然后我们可以使用精确模式匹配来实现。要进行精确模式匹配,我们将使用 ^ 和 $ 字符。我们将在字符串开头添加 ^ 字符,在字符串结尾添加 $ 字符。

员工ID 员工姓名
22 纽马丁
2 Mohan
3 Joe
4 莫汉
100 Guru99
6 古朗
8 Guru999

以下示例显示了如何做到这一点。

使用 $regex Opera模式匹配

db.Employee.find({EmployeeName : {$regex: "^Guru99$"}}).forEach(printjson)

Code 说明:

  1. 在搜索条件中,我们使用了 ^ 和 $ 字符。^ 用于确保字符串以特定字符开头,$ 用于确保字符串以特定字符结尾。因此,代码执行后将只获取名称为“Guru99“。
  2. printjson 用于以更好的方式打印查询返回的每个文档。

如果命令执行成功,将显示以下输出:

输出:

使用 $regex Opera模式匹配

在输出结果中,可以清楚地看到字符串“Guru已获取到“99”。

使用 $options 进行模式匹配

使用 $regex 运算符时,还可以通过使用以下方式提供其他选项: $选项 关键字。例如,假设您想要查找员工姓名中包含“Gu”的所有文档,无论其是否区分大小写。如果想要这样的结果,那么我们需要使用 $选项 启用大小写不敏感参数。

以下示例显示了如何做到这一点。

假设我们有一个员工集合,其中包含名为“Employeeid”和“EmployeeName”的字段。

假设我们馆藏中有以下文件。

员工ID 员工姓名
22 纽马丁
2 Mohan
3 Joe
4 莫汉
100 Guru99
6 古朗
7 古鲁99号

现在,如果我们运行与上一主题相同的查询,我们将永远不会在结果中看到包含“GURU99”的文档。为了确保它出现在结果集中,我们需要添加 `$options "i"` 参数。

使用 $options 进行模式匹配

db.Employee.find({EmployeeName:{$regex: "Gu",$options:'i'}}).forEach(printjson)

Code 说明:

  1. 带有“i”参数的 $options(表示不区分大小写)指定无论找到小写或大写的字母“Gu”,我们都要执行搜索。

如果命令执行成功,将显示以下输出:

输出:

使用 $options 进行模式匹配

  1. 输出结果清楚地表明,即使某个文档中包含大写字母“Gu”,该文档仍然会显示在结果集中。

不使用正则表达式运算符的模式匹配

也可以不使用 $regex 运算符进行模式匹配。以下示例展示了如何实现这一点。

不使用正则表达式的模式匹配 Opera器

db.Employee.find({EmployeeName: /Gu/}).forEach(printjson)

Code 说明:

  1. “//”分隔符的作用是在分隔符内指定搜索条件。因此,我们指定 /Gu/ 来查找员工姓名中包含“Gu”的文档。

如果命令执行成功,将显示以下输出:

输出:

不使用正则表达式的模式匹配 Opera器

输出清楚地显示,返回了员工姓名包含“Gu”字符的那些文档。

从集合中获取最后‘n’个文档

有多种方法可以获取集合中的最后 n 个文档。

让我们通过以下步骤来看一下其中一种方法。

以下示例显示了如何做到这一点。

假设我们有一个员工集合,其中包含名为“Employeeid”和“EmployeeName”的字段。

假设我们的馆藏中有以下文档:

员工ID 员工姓名
22 纽马丁
2 Mohan
3 Joe
4 莫汉
100 Guru99
6 古朗
7 古鲁99号

从集合中获取最后 n 个文档

db.Employee.find().sort({_id:-1}).limit(2).forEach(printjson)

Code 说明:

  1. 查询文档时,请使用排序函数根据集合中 _id 字段的值对记录进行逆序排序。-1 表示按降序(即倒序)对文档进行排序,使最后一个文档显示在最前面。
  2. 然后使用 limit 子句来仅显示所需数量的记录。这里我们设置了 limit 子句 (2),因此它将获取最后两个文档。

如果命令执行成功,将显示以下输出:

输出:

从集合中获取最后 n 个文档

输出清楚地表明,显示了集合中的最后两个文档。因此,我们清楚地表明,要获取集合中的最后“n”个文档,我们可以先按降序对文档进行排序,然后使用 limit 子句返回所需的“n”个文档。

注意::如果搜索的字符串长度超过 38,000 个字符,则不会显示正确的结果。

常见问题

Anchor 包含 ^ 和 $ 的模式。模式“^Guru99美元”仅匹配“Guru99”并拒绝“Guru999”,因为 ^ 表示字符串的开头,$ 表示字符串的结尾。

只有区分大小写且带有 ^ 前缀的模式才能高效地使用索引。未锚定或不区分大小写的模式会触发全集合扫描,因此请尽可能锚定前缀。

在诸如点、星号、加号或括号之类的元字符前加上反斜杠。例如,字面意义上的“.com”结尾的模式会对点进行转义,使其不被视为普通字符。

`$regex` 函数可以对单个字段进行灵活的模式匹配,并且可以扫描整个集合。`$text` 函数使用文本索引,可以跨索引字段进行快速的基于单词的搜索,但不支持部分子字符串模式。

是的。当搜索字符串超过大约 38,000 个字符时,查询可能无法返回正确结果。为了确保匹配的可靠性,请将模式和目标字段的长度控制在这个限制范围内。

存储字段的小写副本以进行不区分大小写的查找,使用 ^ 锚定模式,并且在大集合上优先使用文本索引或 Atlas 搜索,而不是未锚定的 $regex。

AI 助手将纯英文规则转换为 $regex 模式,添加正确的锚点和 $options 标志,并在查询将触发缓慢的全集合扫描时发出警告。

是的。AI 副驾驶会重写未锚定的模式,推荐文本索引或 Atlas 搜索,并将不区分大小写的 $regex 转换为小写字段查找以提高速度。

总结一下这篇文章: