对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。

$ 过滤 (表达式操作符)

$filter

根据指定条件选择要返回的数组的子集。返回一个数组,其中仅包含与条件匹配的元素。返回的元素按原始顺序排列。

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

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

$filter 通过以下语法实现:

{ $filter: { input: <array expression>, as: <string>, arrayIndexAs: <string>, cond: <expression>, limit: <number expression> }}
字段
规范

input

解析为数组的表达式。

如果 input 解析为 null 或指向缺失的字段,则 $filter 返回 null。

如果 input 解析为非数组、非 null 值,则管道将出错。

as

可选。 代表 input 数组中每个元素的变量名称。 如果未指定名称,则变量名称默认为this。

arrayIndexAs

可选.聚合变量的名称,表示当前元素在 input 数组中的索引。第一个数组元素索引为 0。

您可以在表达式中使用变量名称。示例,如果指定 arrayIndexAs: "myIndex",则在表达式中使用 $$myIndex。$$myIndex 返回 input数组中当前元素的索引。

如果省略 arrayIndexAs,则可以在表达式中使用 $$IDX 系统变量来返回当前元素的索引。

有关示例,请参阅 访问数组中每个项目的索引 和 使用 $$IDX 访问索引。

8.3版本新增。

cond

可解析为布尔值的表达式,它可用于确定输出数组中是否应包含某一元素。该表达式使用 as 中指定的变量名称来单独引用 input 数组的每个元素。

limit

可选。一个数字表达式,用于限制 $filter 返回的匹配数组元素的数量。您指定的限制不能小于 1。匹配的数组元素按照它们在输入数组中出现的顺序返回。

如果指定的 limit 大于匹配数组元素的数量,$filter 会返回所有匹配的数组元素。如果限值为 null,$filter 将返回所有匹配的数组元素。

有关表达式的更多信息,请参阅表达式。

例子
结果
{ $filter: { input: [ 1, "a", 2, null, 3.1, Long(4), "5" ], as: "num", cond: { $isNumber: "$$num" } }}

[ 1, 2, 3.1, Long(4) ]

{ $filter: { input: [ 1, "a", 2, null, 3.1, Long(4), "5" ], as: "num", cond: { $isNumber: "$$num" }, limit: 2 }}

[ 1, 2 ]

{ $filter: { input: [ 1, "a", 2, null, 3.1, Long(4), "5" ], as: "num", cond: { $isNumber: "$$num" }, limit: { $add: [ 0, 1 ] } }}

[ 1 ]

以下示例使用包含以下文档的 sales 集合:

db.sales.insertMany( [ { _id: 0, items: [ { item_id: 43, quantity: 2, price: 10, name: "pen" }, { item_id: 2, quantity: 1, price: 240, name: "briefcase" } ] }, { _id: 1, items: [ { item_id: 23, quantity: 3, price: 110, name: "notebook" }, { item_id: 103, quantity: 4, price: 5, name: "pen" }, { item_id: 38, quantity: 1, price: 300, name: "printer" } ] }, { _id: 2, items: [ { item_id: 4, quantity: 1, price: 23, name: "paper" } ] }] )

以下示例将筛选 items 数组,从而使其仅包含 price 大于或等于 100 的文档:

db.sales.aggregate( [ { $project: { items: { $filter: { input: "$items", as: "item", cond: { $gte: [ "$$item.price", 100 ] } } } } }] )
[ { _id: 0, items: [ { item_id: 2, quantity: 1, price: 240, name: 'briefcase' } ] }, { _id: 1, items: [ { item_id: 23, quantity: 3, price: 110, name: 'notebook' }, { item_id: 38, quantity: 1, price: 300, name: 'printer' } ] }, { _id: 2, items: [] }]

该示例使用 limit 字段指定每个 items 数组中返回的匹配元素的数量。

db.sales.aggregate( [ { $project: { items: { $filter: { input: "$items", as: "item", cond: { $gte: [ "$$item.price", 100 ] }, limit: 1 } } } }] )
[ { _id: 0, items: [ { item_id: 2, quantity: 1, price: 240, name: 'briefcase' } ] }, { _id: 1, items: [ { item_id: 23, quantity: 3, price: 110, name: 'notebook' } ] }, { _id: 2, items: [] }]

该示例使用的 limit 字段值大于可返回的匹配元素的可能数量。在这种情况下,limit 不会影响查询结果,而是会返回所有符合 $gte 过滤条件的文档。

db.sales.aggregate( [ { $project: { items: { $filter: { input: "$items", as: "item", cond: { $gte: [ "$$item.price", 100] }, limit: 5 } } } }] )
[ { _id: 0, items: [ { item_id: 2, quantity: 1, price: 240, name: 'briefcase' } ] }, { _id: 1, items: [ { item_id: 23, quantity: 3, price: 110, name: 'notebook' }, { item_id: 38, quantity: 1, price: 300, name: 'printer' } ] }, { _id: 2, items: [] }]

以下聚合筛选 name 值为 pen 的 items。

db.sales.aggregate( [ { $project: { items: { $filter: { input: "$items", as: "item", cond: { $eq: [ "$$item.name", "pen"] } } } } }] )
[ { _id: 0, items: [ { item_id: 43, quantity: 2, price: 10, name: 'pen' } ] }, { _id: 1, items: [ { item_id: 103, quantity: 4, price: 5, name: 'pen' } ] }, { _id: 2, items: [] }]

以下聚合使用 $regexMatch 筛选 name 值以 p 开头的 items:

db.sales.aggregate( [ { $project: { items: { $filter: { input: "$items", as: "item", cond: { $regexMatch: { input: "$$item.name", regex: /^p/ } } } } } }] )
[ { _id: 0, items: [ { item_id: 43, quantity: 2, price: 10, name: 'pen' } ] }, { _id: 1, items: [ { item_id: 103, quantity: 4, price: 5, name: 'pen' }, { item_id: 38, quantity: 1, price: 300, name: 'printer' } ] }, { _id: 2, items: [ { item_id: 4, quantity: 1, price: 23, name: 'paper' } ] }]

使用以下 document 创建名为 people 的示例集合:

db.people.insertMany( [ { _id: 1, name: "Melissa", hobbies: [ "softball", "drawing", "reading" ] }, { _id: 2, name: "Brad", hobbies: [ "gaming", "skateboarding" ] }, { _id: 3, name: "Scott", hobbies: [ "basketball", "music", "fishing" ] }, { _id: 4, name: "Tracey", hobbies: [ "acting", "yoga" ] }, { _id: 5, name: "Josh", hobbies: [ "programming" ] }, { _id: 6, name: "Claire" }] )

hobbies字段包含每个人的爱好数组,按排名顺序排列。数组中的第一个爱好是此人花费最多时间的主节点 (primary node in the replica set)爱好。第一个爱好的数组索引为 0。

以下示例使用 arrayIndexAs。myIndex 变量包含 hobbies数组中每个爱好的索引。该示例返回包含这些document的字段:

  • 人员姓名。

  • secondaryHobbies 数组,其中包含所有其他爱好。

db.people.aggregate( [ { $project: { _id: 0, name: 1, secondaryHobbies: { $filter: { input: "$hobbies", arrayIndexAs: "myIndex", cond: { $eq: [ { $mod: [ "$$myIndex", 2 ] }, 0 ] } } } } }] )

输出:

[ { "name" : "Melissa", "secondaryHobbies" : [ "softball", "reading" ] } { "name" : "Brad", "secondaryHobbies" : [ "gaming" ] } { "name" : "Scott", "secondaryHobbies" : [ "basketball", "fishing" ] } { "name" : "Tracey", "secondaryHobbies" : [ "acting" ] } { "name" : "Josh", "secondaryHobbies" : [ "programming" ] } { "name" : "Claire", "secondaryHobbies" : null }]

$$IDX 变量返回 input 数组中当前元素的索引。如果省略表达式中的 arrayIndexAs字段,则可以使用 $$IDX。

以下示例返回与上一节访问数组中每个项目的索引中的示例相同的document,但使用 $$IDX 而不是 arrayIndexAs:

db.people.aggregate( [ { $project: { _id: 0, name: 1, secondaryHobbies: { $filter: { input: "$hobbies", cond: { $eq: [ { $mod: [ "$$IDX", 2 ] }, 0 ] } } } } }] )