定义
语法
The $regexFindAll operator has the following syntax:
{ $regexFindAll: { input: <expression> , regex: <expression>, options: <expression> } }
字段 | 说明 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
要应用的正则表达式模式。 可以是解析为字符串或正则表达式模式
或者,您也可以使用 选项字段指定 regex 选项。要指定 不能同时在 | |||||||||||
可选。以下 不能同时在
|
返回:
该操作符返回一个数组:
如果该操作符未找到匹配项,则该操作符返回一个空数组。
如果操作符找到匹配项,则该操作符将返回一个文档数组,其中包含每个匹配项的以下信息:
输入中的匹配字符串
the code point index (not byte index) of the matching string in the input, and
与匹配字符串所捕获群组对应的字符串数组。捕获群组在 regex 模式中用未转义括号
()指定。
[ { "match" : <string>, "idx" : <num>, "captures" : <array of strings> }, ... ]
行为
PCRE 库
从版本 6.1 开始,MongoDB 使用 PCRE2(Perl 兼容正则表达式)库来实现正则表达式模式匹配。有关 PCRE2 的更多信息,请参阅 PCRE 文档。。
$regexFindAll 和排序规则
$regexFindAll 的字符串匹配始终区分大小写和变音符号。 $regexFindAll 忽略为集合、db.collection.aggregate() 和索引指定的排序规则(如果使用)。
示例,创建一个排序规则强度为 1 的集合,这意味着排序规则仅比较基本字符,而忽略大小写和变音符号等差异:
db.createCollection( "restaurants", { collation: { locale: "fr", strength: 1 } } )
插入以下文档:
db.restaurants.insertMany( [ { _id: 1, category: "café", status: "Open" }, { _id: 2, category: "cafe", status: "open" }, { _id: 3, category: "cafE", status: "open" } ] )
以下使用集合的排序规则来执行不区分大小写和不区分变音符号的匹配:
db.restaurants.aggregate( [ { $match: { category: "cafe" } } ] )
[ { _id: 1, category: 'café', status: 'Open' }, { _id: 2, category: 'cafe', status: 'open' }, { _id: 3, category: 'cafE', status: 'open' } ]
但是,$regexFindAll 会忽略排序规则。以下正则表达式模式匹配示例区分大小写和变音符号:
db.restaurants.aggregate( [ { $addFields: { resultObject: { $regexFindAll: { input: "$category", regex: /cafe/ } } } } ] ) db.restaurants.aggregate( [ { $addFields: { resultObject: { $regexFindAll: { input: "$category", regex: /cafe/ } } } } ], { collation: { locale: "fr", strength: 1 } } // Ignored in the $regexFindAll )
这两个操作都返回以下内容:
{ "_id" : 1, "category" : "café", "resultObject" : null } { "_id" : 2, "category" : "cafe", "resultObject" : { "match" : "cafe", "idx" : 0, "captures" : [ ] } } { "_id" : 3, "category" : "cafE", "resultObject" : null }
由于该查询忽略排序规则,因此需要与 category 字符串精确匹配(包括大小写和重音符号),这意味着只匹配文档_id: 2。
To perform a case-insensitive regex pattern matching, use the i Option instead. See i Option for an example.
captures 输出行为
If your regex pattern contains capture groups and the pattern finds a match in the input, the captures array in the results corresponds to the groups captured by the matching string. Capture groups are specified with unescaped parentheses () in the regex pattern. The length of the captures array equals the number of capture groups in the pattern and the order of the array matches the order in which the capture groups appear.
创建一个包含以下文档的样本集合 contacts:
db.contacts.insertMany([ { "_id": 1, "fname": "Carol", "lname": "Smith", "phone": "718-555-0113" }, { "_id": 2, "fname": "Daryl", "lname": "Doe", "phone": "212-555-8832" }, { "_id": 3, "fname": "Polly", "lname": "Andrews", "phone": "208-555-1932" }, { "_id": 4, "fname": "Colleen", "lname": "Duncan", "phone": "775-555-0187" }, { "_id": 5, "fname": "Luna", "lname": "Clarke", "phone": "917-555-4414" } ])
The following pipeline applies the regex pattern /(C(ar)*)ol/ to the fname field:
db.contacts.aggregate([ { $project: { returnObject: { $regexFindAll: { input: "$fname", regex: /(C(ar)*)ol/ } } } } ])
The regex pattern finds a match with fname values Carol and Colleen:
{ "_id" : 1, "returnObject" : [ { "match" : "Carol", "idx" : 0, "captures" : [ "Car", "ar" ] } ] } { "_id" : 2, "returnObject" : [ ] } { "_id" : 3, "returnObject" : [ ] } { "_id" : 4, "returnObject" : [ { "match" : "Col", "idx" : 0, "captures" : [ "C", null ] } ] } { "_id" : 5, "returnObject" : [ ] }
The pattern contains the capture group (C(ar)*) which contains the nested group (ar). The elements in the captures array correspond to the two capture groups. If a matching document is not captured by a group (e.g. Colleen and the group (ar)), $regexFindAll replaces the group with a null placeholder.
如上个示例所示,captures 数组为每个捕获组包含一个元素(对非捕获使用 null)。以下示例通过将捕获组的逻辑 or 应用到 phone 字段来搜索具有纽约市区号的电话号码。每组代表纽约市的一个区号:
db.contacts.aggregate([ { $project: { nycContacts: { $regexFindAll: { input: "$phone", regex: /^(718).*|^(212).*|^(917).*/ } } } } ])
For documents which are matched by the regex pattern, the captures array includes the matching capture group and replaces any non-capturing groups with null:
{ "_id" : 1, "nycContacts" : [ { "match" : "718-555-0113", "idx" : 0, "captures" : [ "718", null, null ] } ] } { "_id" : 2, "nycContacts" : [ { "match" : "212-555-8832", "idx" : 0, "captures" : [ null, "212", null ] } ] } { "_id" : 3, "nycContacts" : [ ] } { "_id" : 4, "nycContacts" : [ ] } { "_id" : 5, "nycContacts" : [ { "match" : "917-555-4414", "idx" : 0, "captures" : [ null, null, "917" ] } ] }
示例
$regexFindAll 及其选项
To illustrate the behavior of the $regexFindAll operator as discussed in this example, create a sample collection products with the following documents:
db.products.insertMany([ { _id: 1, description: "Single LINE description." }, { _id: 2, description: "First lines\nsecond line" }, { _id: 3, description: "Many spaces before line" }, { _id: 4, description: "Multiple\nline descriptions" }, { _id: 5, description: "anchors, links and hyperlinks" }, { _id: 6, description: "métier work vocation" } ])
By default, $regexFindAll performs a case-sensitive match. For example, the following aggregation performs a case-sensitive $regexFindAll on the description field. The regex pattern /line/ does not specify any grouping:
db.products.aggregate([ { $addFields: { returnObject: { $regexFindAll: { input: "$description", regex: /line/ } } } } ])
该操作返回以下内容:
{ "_id" : 1, "description" : "Single LINE description.", "returnObject" : [ ] } { "_id" : 2, "description" : "First lines\nsecond line", "returnObject" : [ { "match" : "line", "idx" : 6, "captures" : [ ]}, { "match" : "line", "idx" : 19, "captures" : [ ] } ] } { "_id" : 3, "description" : "Many spaces before line", "returnObject" : [ { "match" : "line", "idx" : 23, "captures" : [ ] } ] } { "_id" : 4, "description" : "Multiple\nline descriptions", "returnObject" : [ { "match" : "line", "idx" : 9, "captures" : [ ] } ] } { "_id" : 5, "description" : "anchors, links and hyperlinks", "returnObject" : [ ] } { "_id" : 6, "description" : "métier work vocation", "returnObject" : [ ] }
以下正则表达式模式 /lin(e|k)/ 在模式中指定分组 (e|k):
db.products.aggregate([ { $addFields: { returnObject: { $regexFindAll: { input: "$description", regex: /lin(e|k)/ } } } } ])
该操作返回以下内容:
{ "_id" : 1, "description" : "Single LINE description.", "returnObject": [ ] } { "_id" : 2, "description" : "First lines\nsecond line", "returnObject" : [ { "match" : "line", "idx" : 6, "captures" : [ "e" ] }, { "match" : "line", "idx" : 19, "captures" : [ "e" ] } ] } { "_id" : 3, "description" : "Many spaces before line", "returnObject" : [ { "match" : "line", "idx" : 23, "captures" : [ "e" ] } ] } { "_id" : 4, "description" : "Multiple\nline descriptions", "returnObject" : [ { "match" : "line", "idx" : 9, "captures" : [ "e" ] } ] } { "_id" : 5, "description" : "anchors, links and hyperlinks", "returnObject" : [ { "match" : "link", "idx" : 9, "captures" : [ "k" ] }, { "match" : "link", "idx" : 24, "captures" : [ "k" ] } ] } { "_id" : 6, "description" : "métier work vocation", "returnObject" : [ ] }
In the return option, the idx field is the code point index and not the byte index. To illustrate, consider the following example that uses the regex pattern /tier/:
db.products.aggregate([ { $addFields: { returnObject: { $regexFindAll: { input: "$description", regex: /tier/ } } } } ])
该操作会返回以下内容,其中只有最后一条记录与模式匹配,并且返回的 idx 为 2(如果使用字节索引,则返回 3)
{ "_id" : 1, "description" : "Single LINE description.", "returnObject" : [ ] } { "_id" : 2, "description" : "First lines\nsecond line", "returnObject" : [ ] } { "_id" : 3, "description" : "Many spaces before line", "returnObject" : [ ] } { "_id" : 4, "description" : "Multiple\nline descriptions", "returnObject" : [ ] } { "_id" : 5, "description" : "anchors, links and hyperlinks", "returnObject" : [ ] } { "_id" : 6, "description" : "métier work vocation", "returnObject" : [ { "match" : "tier", "idx" : 2, "captures" : [ ] } ] }
i 选项
注意
不能同时在 regex 和 options 字段中指定选项。
要执行不区分大小写的模式匹配,将 i 选项作为正则表达式字段的一部分或纳入选项字段:
// Specify i as part of the regex field { $regexFindAll: { input: "$description", regex: /line/i } } // Specify i in the options field { $regexFindAll: { input: "$description", regex: /line/, options: "i" } } { $regexFindAll: { input: "$description", regex: "line", options: "i" } }
For example, the following aggregation performs a case-insensitive $regexFindAll on the description field. The regex pattern /line/ does not specify any grouping:
db.products.aggregate([ { $addFields: { returnObject: { $regexFindAll: { input: "$description", regex: /line/i } } } } ])
该操作将返回以下文档:
{ "_id" : 1, "description" : "Single LINE description.", "returnObject" : [ { "match" : "LINE", "idx" : 7, "captures" : [ ] } ] } { "_id" : 2, "description" : "First lines\nsecond line", "returnObject" : [ { "match" : "line", "idx" : 6, "captures" : [ ] }, { "match" : "line", "idx" : 19, "captures" : [ ] } ] } { "_id" : 3, "description" : "Many spaces before line", "returnObject" : [ { "match" : "line", "idx" : 23, "captures" : [ ] } ] } { "_id" : 4, "description" : "Multiple\nline descriptions", "returnObject" : [ { "match" : "line", "idx" : 9, "captures" : [ ] } ] } { "_id" : 5, "description" : "anchors, links and hyperlinks", "returnObject" : [ ] } { "_id" : 6, "description" : "métier work vocation", "returnObject" : [ ] }
m 选项
注意
不能同时在 regex 和 options 字段中指定选项。
要匹配多行字符串中每一行的指定锚点(如 ^、$ ),请在 regex 字段或选项字段中包含 m 选项:
// Specify m as part of the regex field { $regexFindAll: { input: "$description", regex: /line/m } } // Specify m in the options field { $regexFindAll: { input: "$description", regex: /line/, options: "m" } } { $regexFindAll: { input: "$description", regex: "line", options: "m" } }
以下示例同时包含 i 和 m 选项,用于为多行字符串匹配以字母 s 或 S 开头的行:
db.products.aggregate([ { $addFields: { returnObject: { $regexFindAll: { input: "$description", regex: /^s/im } } } } ])
该操作返回以下内容:
{ "_id" : 1, "description" : "Single LINE description.", "returnObject" : [ { "match" : "S", "idx" : 0, "captures" : [ ] } ] } { "_id" : 2, "description" : "First lines\nsecond line", "returnObject" : [ { "match" : "s", "idx" : 12, "captures" : [ ] } ] } { "_id" : 3, "description" : "Many spaces before line", "returnObject" : [ ] } { "_id" : 4, "description" : "Multiple\nline descriptions", "returnObject" : [ ] } { "_id" : 5, "description" : "anchors, links and hyperlinks", "returnObject" : [ ] } { "_id" : 6, "description" : "métier work vocation", "returnObject" : [ ] }
x 选项
注意
不能同时在 regex 和 options 字段中指定选项。
要忽略模式中所有未转义的空格字符和注释(由未转义的哈希 # 字符和下一个换行符表示),请在选项字段中包含 s 选项:
// Specify x in the options field { $regexFindAll: { input: "$description", regex: /line/, options: "x" } } { $regexFindAll: { input: "$description", regex: "line", options: "x" } }
以下示例纳入 x 选项来跳过非转义空格和注释:
db.products.aggregate([ { $addFields: { returnObject: { $regexFindAll: { input: "$description", regex: /lin(e|k) # matches line or link/, options:"x" } } } } ])
该操作返回以下内容:
{ "_id" : 1, "description" : "Single LINE description.", "returnObject" : [ ] } { "_id" : 2, "description" : "First lines\nsecond line", "returnObject" : [ { "match" : "line", "idx" : 6, "captures" : [ "e" ] }, { "match" : "line", "idx" : 19, "captures" : [ "e" ] } ] } { "_id" : 3, "description" : "Many spaces before line", "returnObject" : [ { "match" : "line", "idx" : 23, "captures" : [ "e" ] } ] } { "_id" : 4, "description" : "Multiple\nline descriptions", "returnObject" : [ { "match" : "line", "idx" : 9, "captures" : [ "e" ] } ] } { "_id" : 5, "description" : "anchors, links and hyperlinks", "returnObject" : [ { "match" : "link", "idx" : 9, "captures" : [ "k" ] }, { "match" : "link", "idx" : 24, "captures" : [ "k" ] } ] } { "_id" : 6, "description" : "métier work vocation", "returnObject" : [ ] }
s 选项
注意
不能同时在 regex 和 options 字段中指定选项。
要支持模式中的点字符(即 .)匹配包括换行符在内的所有字符,请在选项字段中加入 s 选项:
// Specify s in the options field { $regexFindAll: { input: "$description", regex: /m.*line/, options: "s" } } { $regexFindAll: { input: "$description", regex: "m.*line", options: "s" } }
下面的示例包含 s 选项,允许使用点字符(即“.”)来匹配包括新行在内的所有字符,以及使用 i 选项来执行不区分大小写的匹配:
db.products.aggregate([ { $addFields: { returnObject: { $regexFindAll: { input: "$description", regex:/m.*line/, options: "si" } } } } ])
该操作返回以下内容:
{ "_id" : 1, "description" : "Single LINE description.", "returnObject" : [ ] } { "_id" : 2, "description" : "First lines\nsecond line", "returnObject" : [ ] } { "_id" : 3, "description" : "Many spaces before line", "returnObject" : [ { "match" : "Many spaces before line", "idx" : 0, "captures" : [ ] } ] } { "_id" : 4, "description" : "Multiple\nline descriptions", "returnObject" : [ { "match" : "Multiple\nline", "idx" : 0, "captures" : [ ] } ] } { "_id" : 5, "description" : "anchors, links and hyperlinks", "returnObject" : [ ] } { "_id" : 6, "description" : "métier work vocation", "returnObject" : [ ] }
使用 $regexFindAll 从 String 中解析电子邮件
使用以下文档创建样本collectionfeedback :
db.feedback.insertMany([ { "_id" : 1, comment: "Hi, I'm just reading about MongoDB -- aunt.arc.tica@example.com" }, { "_id" : 2, comment: "I wanted to concatenate a string" }, { "_id" : 3, comment: "How do I convert a date to string? Contact me at either cam@mongodb.com or c.dia@mongodb.com" }, { "_id" : 4, comment: "It's just me. I'm testing. fred@MongoDB.com" } ])
The following aggregation uses the $regexFindAll to extract all emails from the comment field (case insensitive).
db.feedback.aggregate( [ { $addFields: { "email": { $regexFindAll: { input: "$comment", regex: /[a-z0-9_.+-]+@[a-z0-9_.+-]+\.[a-z0-9_.+-]+/i } } } }, { $set: { email: "$email.match"} } ] )
- 第一个阶段:
The stage uses the
$addFieldsstage to add a new fieldemailto the document. The new field is an array that contains the result of performing the$regexFindAllon thecommentfield:{ "_id" : 1, "comment" : "Hi, I'm just reading about MongoDB -- aunt.arc.tica@example.com", "email" : [ { "match" : "aunt.arc.tica@example.com", "idx" : 38, "captures" : [ ] } ] } { "_id" : 2, "comment" : "I wanted to concatenate a string", "email" : [ ] } { "_id" : 3, "comment" : "How do I convert a date to string? Contact me at either cam@mongodb.com or c.dia@mongodb.com", "email" : [ { "match" : "cam@mongodb.com", "idx" : 56, "captures" : [ ] }, { "match" : "c.dia@mongodb.com", "idx" : 75, "captures" : [ ] } ] } { "_id" : 4, "comment" : "It's just me. I'm testing. fred@MongoDB.com", "email" : [ { "match" : "fred@MongoDB.com", "idx" : 28, "captures" : [ ] } ] } - 第二阶段
此阶段使用
$set阶段将email数组元素重置为"email.match"值。如果email的当前值为 null,则会将email的新值设为 null。{ "_id" : 1, "comment" : "Hi, I'm just reading about MongoDB -- aunt.arc.tica@example.com", "email" : [ "aunt.arc.tica@example.com" ] } { "_id" : 2, "comment" : "I wanted to concatenate a string", "email" : [ ] } { "_id" : 3, "comment" : "How do I convert a date to string? Contact me at either cam@mongodb.com or c.dia@mongodb.com", "email" : [ "cam@mongodb.com", "c.dia@mongodb.com" ] } { "_id" : 4, "comment" : "It's just me. I'm testing. fred@MongoDB.com", "email" : [ "fred@MongoDB.com" ] }
使用捕获的分组来解析用户名
使用以下文档创建样本collectionfeedback :
db.feedback.insertMany([ { "_id" : 1, comment: "Hi, I'm just reading about MongoDB -- aunt.arc.tica@example.com" }, { "_id" : 2, comment: "I wanted to concatenate a string" }, { "_id" : 3, comment: "How do I convert a date to string? Contact me at either cam@mongodb.com or c.dia@mongodb.com" }, { "_id" : 4, comment: "It's just me. I'm testing. fred@MongoDB.com" } ])
To reply to the feedback, assume you want to parse the local-part of the email address to use as the name in the greetings. Using the captured field returned in the $regexFindAll results, you can parse out the local part of each email address:
db.feedback.aggregate( [ { $addFields: { "names": { $regexFindAll: { input: "$comment", regex: /([a-z0-9_.+-]+)@[a-z0-9_.+-]+\.[a-z0-9_.+-]+/i } }, } }, { $set: { names: { $reduce: { input: "$names.captures", initialValue: [ ], in: { $concatArrays: [ "$$value", "$$this" ] } } } } } ] )
- 第一个阶段:
The stage uses the
$addFieldsstage to add a new fieldnamesto the document. The new field contains the result of performing the$regexFindAllon thecommentfield:{ "_id" : 1, "comment" : "Hi, I'm just reading about MongoDB -- aunt.arc.tica@example.com", "names" : [ { "match" : "aunt.arc.tica@example.com", "idx" : 38, "captures" : [ "aunt.arc.tica" ] } ] } { "_id" : 2, "comment" : "I wanted to concatenate a string", "names" : [ ] } { "_id" : 3, "comment" : "How do I convert a date to string? Contact me at either cam@mongodb.com or c.dia@mongodb.com", "names" : [ { "match" : "cam@mongodb.com", "idx" : 56, "captures" : [ "cam" ] }, { "match" : "c.dia@mongodb.com", "idx" : 75, "captures" : [ "c.dia" ] } ] } { "_id" : 4, "comment" : "It's just me. I'm testing. fred@MongoDB.com", "names" : [ { "match" : "fred@MongoDB.com", "idx" : 28, "captures" : [ "fred" ] } ] } - 第二阶段
该阶段使用
$set阶段和$reduce操作符,将names重置为包含"$names.captures"元素的数组。{ "_id" : 1, "comment" : "Hi, I'm just reading about MongoDB -- aunt.arc.tica@example.com", "names" : [ "aunt.arc.tica" ] } { "_id" : 2, "comment" : "I wanted to concatenate a string", "names" : [ ] } { "_id" : 3, "comment" : "How do I convert a date to string? Contact me at either cam@mongodb.com or c.dia@mongodb.com", "names" : [ "cam", "c.dia" ] } { "_id" : 4, "comment" : "It's just me. I'm testing. fred@MongoDB.com", "names" : [ "fred" ] }
提示
For more information on the behavior of the captures array and additional examples, see captures Output Behavior.