db.collection.aggregate 阶段
前言
一、$addFields
1.1 认识
$addFields
为文档添加新字段。与 $project
类似,$addFields
重塑了流中的每个文档;具体来说,就是在输出文档中添加新字段,这些输出文档既包含输入文档中的现有字段,也包含新添加的字段。
1.2 语法
1.3 用法
二、$bucket
2.1 认识
$bucket
根据指定的表达式和存储桶边界将传入的文档分为多个组(称为存储桶)。
2.2 语法
2.3 用法
三、$bucketAuto
3.1 认识
$bucketAuto
根据指定的表达式,将接收到的文档归类到特定数量的群组中(称为“存储桶”)。自动确定存储桶边界,以尝试将文档均匀地分配到指定数量的存储桶中。
3.2 语法
3.3 用法
四、$changeStream
4.1 认识
$changeStream
返回集合的 Change Stream
游标。此阶段只能在 aggregation pipeline
中发生一次,并且必须作为第一阶段发生。
4.2 语法
4.3 用法
五、$changeStreamSplitLargeEvent
5.1 认识
$changeStreamSplitLargeEvent
将超过 16 MB 的大型 change stream
事件分割成较小的分段,在 change stream
游标中返回。
5.2 语法
5.3 用法
六、$collStats
6.1 认识
$collStats
返回有关集合或视图的统计信息。
6.2 语法
6.3 用法
七、$count
7.1 认识
$count
返回聚合管道此阶段的文档数量计数。
7.2 语法
7.3 用法
八、$densify
8.1 认识
$densify
在文档序列中创建新文档,其中缺少字段中的某些值。
8.2 语法
8.3 用法
九、$documents
9.1 认识
$documents
从输入表达式返回字面文档。
9.2 语法
9.3 用法
十、$facet
10.1 认识
$facet
在单个阶段内处理同一组输入文档上的多个聚合管道。支持创建多分面聚合,能够在单个阶段中跨多个维度或分面描述数据特征。理解: 在 MongoDB
中,$facet
是聚合管道的一个阶段,它允许你在同一个聚合查询中并行运行多个子管道, 可以并行处理, 每个子管道可以独立处理相同的一组输入文档,并生成各自的输出。这样你就可以一次性获得多种不同角度的聚合结果,而无需多次查询。 注意: $facet
在管道中的第一个阶段, 不会使用索引, 所以, 不要将 $facet
放到第一阶段。
10.2 语法
{ $facet:
{
<outputField1>: [ <stage1>, <stage2>, ... ],
<outputField2>: [ <stage1>, <stage2>, ... ],
...
}
}
10.3 用法
db.news.aggregate([
{
$match: {
$expr: { $eq: ["$userId", ObjectId("67c3cfd283b91d12a8aa61dd")] },
},
},
{
$facet: {
list: [{ $sort: { createdAt: -1 } }, { $limit: 20 }],
total: [{ $count: "count" }],
},
},
{
$project: {
list: 1,
total: { $arrayElemAt: ["$total.count", 0] },
},
},
]);
-
子管道一: 根据
createdAt
排序, 并获取前20
条文档。子管道一会输出list
字段。 -
子管道二: 计算
67c3cfd283b91d12a8aa61dd
下的文档总数。子管道二会输出total
字段。
十一、$fill
11.1 认识
$fill
填充文档中的 null
和缺失的字段值。
11.2 语法
11.3 用法
十二、$geoNear
12.1 认识
$geoNear
根据与地理空间点的接近程度返回有序的文档流。针对地理空间数据,整合了 $match
、$sort
和 $limit
功能。输出文档包含一个额外的距离字段,并可包含一个位置标识符字段。
12.2 语法
12.3 用法
十三、$graphLookup
13.1 认识
$graphLookup
对集合执行递归搜索。为每个输出文档添加一个新数组字段,其中包含该文档的递归搜索遍历结果。
13.2 语法
13.3 用法
十四、$group
14.1 认识
$group
按指定的标识符表达式对输入文档进行分组,并将累加器表达式(如果指定)应用于每个群组。接收所有输入文档,并为每个不同群组输出一个文档。输出文档仅包含标识符字段和累积字段(如果指定)。
14.2 语法
{
$group:
{
_id: <expression>, // Group key
<field1>: { <accumulator1> : <expression1> },
...
}
}
-
_id
: 必需。_id
表达式指定群组键。 如果指定的_id
值为空值或任何其他常量值,$group
阶段将返回聚合所有输入文档值的单个文档。 -
field
: 可选。使用累加器操作符进行计算。-
$sum
:{ $sum: <expression> }
或者{ $sum: [ <expression1>, <expression2> ... ] }
。{ $sum: 1 }
统计分组文档数量 -
$avg
:{ $avg: <expression> }
或者{ $avg: [ <expression1>, <expression2> ... ] }
-
$max
:{ $max: <expression> }
-
$min
:{ $min: <expression> }
-
$count
:{ $count: { } }
, 不接受任何参数。$count
在功能上等同于在$group
阶段使用{ $sum : 1 }
。 -
$multiply
:{ $multiply: [ <expression1>, <expression2>, ... ] }
-
14.3 用法
db.transactions.insertMany([ { symbol: "600519", qty: 100, price: 567.4, currency: "CNY" }, { symbol: "AMZN", qty: 1, price: 1377.5, currency: "USD" }, { symbol: "AAPL", qty: 2, price: 150.7, currency: "USD"} ]);
// 根据 currency 进行分组, currency 相同的为一组。因此, 不使用聚合操作符的情况下, $group 可以返回管道文档中某一字段的所有值(不重复)
db.transactions.aggregate([ { $group: { _id: "$currency" } } ]);
// 输出结果:
[ { _id: 'USD' }, { _id: 'CNY' } ]
// 根据 currency 进行分组, currency 相同的为一组。增加 totalQty 字段, 表示 qty 的总和; 增加 totalNotional 字段, 表示 价格 * 数量 的总和; 增加 avgPrice 字段, 表示 price 的平均值; 增加 count 字段, 表示这个分组有多少篇文档; 增加 maxNotional 字段, 求出该分组中 价格 * 数量 中的最大值; minNotional 同理。
db.transactions.aggregate([ { $group: { _id: "$currency", totalQty: { $sum: "$qty" }, totalNotional: { $sum: { $multiply: [ "$price", "$qty" ] } }, avgPrice: { $avg: "$price" }, count: { $sum: 1 }, maxNotional: { $max: { $multiply: [ "$price", "$qty" ] } }, minNotional: { $min: {$multiply: [ "$price", "$qty" ] } } } } ]);
// 输出结果:
[
{
_id: 'USD',
totalQty: 3,
totalNotional: 1678.9,
avgPrice: 764.1,
count: 2,
maxNotional: 1377.5,
minNotional: 301.4
},
{
_id: 'CNY',
totalQty: 100,
totalNotional: 56740,
avgPrice: 567.4,
count: 1,
maxNotional: 56740,
minNotional: 56740
}
]
// 将整个集合分为一组, 再此基础上进行聚合操作
db.transactions.aggregate([ { $group: { _id: null, totalQty: { $sum: "$qty" }, totalNotional: { $sum: { $multiply: [ "$price", "$qty" ] } }, avgPrice: { $avg: "$price" }, count: { $sum: 1 }, maxNotional: { $max: { $multiply: [ "$price", "$qty" ] } }, minNotional: { $min: {$multiply: [ "$price", "$qty" ] } } } } ]);
// 输出结果为:
[
{
_id: null,
totalQty: 103,
totalNotional: 58418.9,
avgPrice: 698.5333333333333,
count: 3,
maxNotional: 56740,
minNotional: 301.4
}
]
十五、$indexStats
15.1 认识
$indexStats
返回有关集合的每个索引使用情况的统计信息。
15.2 语法
15.3 用法
十六、$limit
16.1 认识
$limit
将未修改的前 n 个文档传递到管道,其中 n 为指定的限制。对于每个输入文档,输出一个文档(针对前 n 个文档)或零个文档(前 n 个文档之后)。
16.2 语法
16.3 用法
$limit
筛选出管道内前 N
篇文档
// 新增几个文档
db.user1.insertMany([ { name: { firstName: "alice", lastName: "wong" }, balance: 50}, { name: { firstName: "bob", lastName: "yang" }, balance: 20}])
// $limit 筛选出管道内前 N 篇文档
db.user1.aggregate([ { $limit: 1} ]);
十七、$listSampledQueries
17.1 认识
$listSampledQueries
列出所有集合或特定集合的抽样查询。
17.2 语法
17.3 用法
十八、$listSearchIndexes
18.1 认识
$listSearchIndexes
返回指定集合上现有 Atlas Search 索引的信息。
18.2 语法
18.3 用法
十九、$listSessions
19.1 认识
$listSessions
列出活动时间足够长、足以传播到 system.sessions
集合的所有会话。
19.2 语法
19.3 用法
二十、$lookup
20.1 认识
$lookup
对同一数据库中的一个集合执行 左外连接, 以过滤 已连接 集合中的文档以便进行处理。$lookup
阶段向每个输入文档添加一个新的数组字段。这新的数组字段包含来自 已连接 集合的匹配文档。$lookup
阶段将这些重塑后的文档传递给下一阶段。
20.2 语法
单个条件联接的等值匹配: 要在输入文档中的字段与 已连接 集合文档中的字段之间执行等值匹配
{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}
-
from
: 在同一个数据库中指定待执行联接操作的集合。from
是可选的,您可以改为在$documents
阶段中使用$lookup
阶段。从MongoDB 5.1
开始,可以对from
参数中指定的集合进行分片。 -
localField
: 指定本地文档的localField
对外部文档的foreignField
执行等值匹配。如果本地文档不包含localField
值,则 将使用$lookup null
值进行匹配。 -
foreignField
: 指定外部文档的foreignField
(指定来自from
集合中的文档的字段)对本地文档的localField
执行等值匹配。如果外部文档不包含foreignField
值,则 将使用$lookup null
值进行匹配。 -
as
: 指定要添加到输入文档中的新数组字段的名称。新数组字段包含来自from
集合的匹配文档。如果输入文档中已存在指定的名称,现有字段将被重写。
关联管道子查询联接: 在 MongoDB
中,关联子查询是 $lookup
阶段中的管道,引用了联接集合中的文档字段。
{
$lookup:
{
from: <joined collection>,
let: { <var_1>: <expression>, …, <var_n>: <expression> },
pipeline: [ <pipeline to run on joined collection> ],
as: <output array field>
}
}
-
form
: 在同一个数据库中指定待执行联接操作的集合。from
是可选的,您可以改为在$documents
阶段中使用$lookup
阶段。从MongoDB 5.1
开始,from
集合可以分片。 -
let
: 可选。 指定要在管道阶段 外部文档 使用的变量。使用变量表达式访问权限输入到pipeline
的文档字段。let
中如果要引用 当前(自身)文档 管道阶段的变量、或者 当前(自身)文档 的字段名, 需要使用$<variable>
字段表达式。如果,let
定义好的变量要在pipeline
中引用,pipeline
需要使用$$<variable>
来引用let
变量。 -
pipeline
: 指定在外部集合上运行的pipeline
。pipeline
返回外部集合的文档。要返回所有文档,请指定一个空的pipeline []
。pipeline
无法直接访问当前 当前(自身)文档 字段。 需要使用let
选项为 当前(自身)文档 字段定义变量,然后在pipeline
阶段引用 当前(自身)文档 变量。let
定义好的变量要在pipeline
中引用,pipeline
需要使用$$<variable>
来引用let
变量。也就是说:pipeline
运行的是 外部文档,let
声明的是 当前(自身)文档, 外部文档 不能直接访问 当前(自身)文档。-
pipeline $match
阶段:pipeline $match
阶段 需要使用$expr
来允许在pipeline $match
阶段 中使用聚合表达式, 进而{
let: { price: "$selfPrice" }, // price 为 let 定义的变量, $selfPrice 是自身集合的字段名 price, 但是, 在 let 中访问需要加 $
pipeline: [ { $match: { $expr: { $eq: ["$$price", "$price"] } } } ], // 比较当前自身文档的 $$pricer 与 外部文档的 $price 是否相等。
} -
管道中的其他(非
$match
)阶段不需要$expr
操作符符来访问权限变量。
-
-
as
: 指定要添加到已连接文档的新数量字段的名称。新的大量字段包含来自加入的收集的匹配文档。如果指定的名称已存在于所连接的文档中,则现有字段将被覆盖。
非关联管道子查询联接: 在 MongoDB
中,非关联子查询是 $lookup
阶段中的管道, 没有引用联接集合中的文档字段。
{
$lookup:
{
from: <joined collection>,
pipeline: [ <pipeline to run on joined collection> ],
as: <output array field>
}
}
关联管道子查询联接并进行单条件等值匹配:
{
$lookup:
{
from: <foreign collection>,
localField: <field from local collection's documents>,
foreignField: <field from foreign collection's documents>,
let: { <var_1>: <expression>, …, <var_n>: <expression> },
pipeline: [ <pipeline to run> ],
as: <output array field>
}
}
20.3 用法
单个条件联接的等值匹配: localField
字段值会与 foreignField
字段值进行等值匹配
db.user1.insertMany([ { name: { firstName: "alice", lastName: "wong" }, balance: 50, currency: ["CNY", "USD"]}, { name: { firstName: "bob", lastName: "yang" }, balance: 20, currency: ["GBP"]}, { name: { firstName: "charlie", lastName: "gordon" }, balance: 100},{ name: { firstName: "david", lastName: "wu" }, balance: 200, currency: []}, { name: { firstName: "eddie", lastName: "kim" }, balance: 20, currency: null} ]);
db.forex.insertMany([ { ccy: "USD", rate: 6.91, date: new Date("2018-12-21" ) }, { ccy: "GBP", rate: 8.72, date: new Date("2018-08-21" ) }, { ccy: "CNY", rate: 1.0, date: new Date("2018-12-21" ) } ]);
//
db.user1.aggregate([ { $lookup: { from: "forex", localField: "currency", foreignField: "ccy", as: "forexData" } } ]);
// 输出结果为:
[
{
_id: ObjectId('67bf93c73d5b2b20ce11cbca'),
name: { firstName: 'alice', lastName: 'wong' },
balance: 50,
currency: [ 'CNY', 'USD' ],
forexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd2'),
ccy: 'USD',
rate: 6.91,
date: ISODate('2018-12-21T00:00:00.000Z')
},
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd4'),
ccy: 'CNY',
rate: 1,
date: ISODate('2018-12-21T00:00:00.000Z')
}
]
},
{
_id: ObjectId('67bf93c73d5b2b20ce11cbcb'),
name: { firstName: 'bob', lastName: 'yang' },
balance: 20,
currency: [ 'GBP' ],
forexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd3'),
ccy: 'GBP',
rate: 8.72,
date: ISODate('2018-08-21T00:00:00.000Z')
}
]
},
{
_id: ObjectId('67bf9fdd3d5b2b20ce11cbcf'),
name: { firstName: 'charlie', lastName: 'gordon' },
balance: 100,
forexData: []
},
{
_id: ObjectId('67bf9fdd3d5b2b20ce11cbd0'),
name: { firstName: 'david', lastName: 'wu' },
balance: 200,
currency: [],
forexData: []
},
{
_id: ObjectId('67bf9fdd3d5b2b20ce11cbd1'),
name: { firstName: 'eddie', lastName: 'kim' },
balance: 20,
currency: null,
forexData: []
}
]
//
db.user1.aggregate([ { $unwind: { path: "$currency" }}, { $lookup: { from: "forex", localField: "currency", foreignField: "ccy", as: "forexData" } }]);
[
{
_id: ObjectId('67bf93c73d5b2b20ce11cbca'),
name: { firstName: 'alice', lastName: 'wong' },
balance: 50,
currency: 'CNY',
forexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd4'),
ccy: 'CNY',
rate: 1,
date: ISODate('2018-12-21T00:00:00.000Z')
}
]
},
{
_id: ObjectId('67bf93c73d5b2b20ce11cbca'),
name: { firstName: 'alice', lastName: 'wong' },
balance: 50,
currency: 'USD',
forexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd2'),
ccy: 'USD',
rate: 6.91,
date: ISODate('2018-12-21T00:00:00.000Z')
}
]
},
{
_id: ObjectId('67bf93c73d5b2b20ce11cbcb'),
name: { firstName: 'bob', lastName: 'yang' },
balance: 20,
currency: 'GBP',
forexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd3'),
ccy: 'GBP',
rate: 8.72,
date: ISODate('2018-08-21T00:00:00.000Z')
}
]
}
]
非关联管道子查询联接
db.user1.insertMany([ { name: { firstName: "alice", lastName: "wong" }, balance: 50, currency: ["CNY", "USD"]}, { name: { firstName: "bob", lastName: "yang" }, balance: 20, currency: ["GBP"]}, { name: { firstName: "charlie", lastName: "gordon" }, balance: 100},{ name: { firstName: "david", lastName: "wu" }, balance: 200, currency: []}, { name: { firstName: "eddie", lastName: "kim" }, balance: 20, currency: null} ]);
db.forex.insertMany([ { ccy: "USD", rate: 6.91, date: new Date("2018-12-21" ) }, { ccy: "GBP", rate: 8.72, date: new Date("2018-08-21" ) }, { ccy: "CNY", rate: 1.0, date: new Date("2018-12-21" ) } ]);
// $lookup 子查询不相关联接
db.user1.aggregate([ { $lookup: { from: "forex", pipeline: [ { $match: { date: new Date("2018-12-21") } } ] , as: "forexData"} } ]);
// 结果如下:
[
{
_id: ObjectId('67bf93c73d5b2b20ce11cbca'),
name: { firstName: 'alice', lastName: 'wong' },
balance: 50,
currency: [ 'CNY', 'USD' ],
forexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd2'),
ccy: 'USD',
rate: 6.91,
date: ISODate('2018-12-21T00:00:00.000Z')
},
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd4'),
ccy: 'CNY',
rate: 1,
date: ISODate('2018-12-21T00:00:00.000Z')
}
]
},
{
_id: ObjectId('67bf93c73d5b2b20ce11cbcb'),
name: { firstName: 'bob', lastName: 'yang' },
balance: 20,
currency: [ 'GBP' ],
forexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd2'),
ccy: 'USD',
rate: 6.91,
date: ISODate('2018-12-21T00:00:00.000Z')
},
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd4'),
ccy: 'CNY',
rate: 1,
date: ISODate('2018-12-21T00:00:00.000Z')
}
]
},
{
_id: ObjectId('67bf9fdd3d5b2b20ce11cbcf'),
name: { firstName: 'charlie', lastName: 'gordon' },
balance: 100,
forexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd2'),
ccy: 'USD',
rate: 6.91,
date: ISODate('2018-12-21T00:00:00.000Z')
},
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd4'),
ccy: 'CNY',
rate: 1,
date: ISODate('2018-12-21T00:00:00.000Z')
}
]
},
{
_id: ObjectId('67bf9fdd3d5b2b20ce11cbd0'),
name: { firstName: 'david', lastName: 'wu' },
balance: 200,
currency: [],
forexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd2'),
ccy: 'USD',
rate: 6.91,
date: ISODate('2018-12-21T00:00:00.000Z')
},
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd4'),
ccy: 'CNY',
rate: 1,
date: ISODate('2018-12-21T00:00:00.000Z')
}
]
},
{
_id: ObjectId('67bf9fdd3d5b2b20ce11cbd1'),
name: { firstName: 'eddie', lastName: 'kim' },
balance: 20,
currency: null,
forexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd2'),
ccy: 'USD',
rate: 6.91,
date: ISODate('2018-12-21T00:00:00.000Z')
},
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd4'),
ccy: 'CNY',
rate: 1,
date: ISODate('2018-12-21T00:00:00.000Z')
}
]
}
]
关联管道子查询联接
db.user1.insertMany([ { name: { firstName: "alice", lastName: "wong" }, balance: 50, currency: ["CNY", "USD"]}, { name: { firstName: "bob", lastName: "yang" }, balance: 20, currency: ["GBP"]}, { name: { firstName: "charlie", lastName: "gordon" }, balance: 100},{ name: { firstName: "david", lastName: "wu" }, balance: 200, currency: []}, { name: { firstName: "eddie", lastName: "kim" }, balance: 20, currency: null} ]);
db.forex.insertMany([ { ccy: "USD", rate: 6.91, date: new Date("2018-12-21" ) }, { ccy: "GBP", rate: 8.72, date: new Date("2018-08-21" ) }, { ccy: "CNY", rate: 1.0, date: new Date("2018-12-21" ) } ]);
// $lookup 子查询相关联接
db.user1.aggregate([ { $lookup: { from: "forex", let: { bal: "$balance" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: [ "$date", new Date("2018-12-21" )] }, { $gt: [ "$$bal", 100 ]} ] } } } ], as: "froexData" } } ]);
// 输出结果
[
{
_id: ObjectId('67bf93c73d5b2b20ce11cbca'),
name: { firstName: 'alice', lastName: 'wong' },
balance: 50,
currency: [ 'CNY', 'USD' ],
froexData: []
},
{
_id: ObjectId('67bf93c73d5b2b20ce11cbcb'),
name: { firstName: 'bob', lastName: 'yang' },
balance: 20,
currency: [ 'GBP' ],
froexData: []
},
{
_id: ObjectId('67bf9fdd3d5b2b20ce11cbcf'),
name: { firstName: 'charlie', lastName: 'gordon' },
balance: 100,
froexData: []
},
{
_id: ObjectId('67bf9fdd3d5b2b20ce11cbd0'),
name: { firstName: 'david', lastName: 'wu' },
balance: 200,
currency: [],
froexData: [
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd2'),
ccy: 'USD',
rate: 6.91,
date: ISODate('2018-12-21T00:00:00.000Z')
},
{
_id: ObjectId('67bfa3853d5b2b20ce11cbd4'),
ccy: 'CNY',
rate: 1,
date: ISODate('2018-12-21T00:00:00.000Z')
}
]
},
{
_id: ObjectId('67bf9fdd3d5b2b20ce11cbd1'),
name: { firstName: 'eddie', lastName: 'kim' },
balance: 20,
currency: null,
froexData: []
}
]
20.4 联系
单个条件联接的等值匹配 等于于如下 SQL
语句
SELECT *, (
SELECT ARRAY_AGG(*)
FROM <collection to join>
WHERE <foreignField> = <collection.localField>
) AS <output array field>
FROM collection;
关联管道子查询联接 等于于如下 SQL
语句
SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (
SELECT <documents as determined from the pipeline>
FROM <collection to join>
WHERE <pipeline>
);
关联管道子查询联接并进行单条件等值匹配 等同于如下 SQL
语句
SELECT *, <output array field>
FROM localCollection
WHERE <output array field> IN (
SELECT <documents as determined from the pipeline>
FROM <foreignCollection>
WHERE <foreignCollection.foreignField> = <localCollection.localField>
AND <pipeline match condition>
);
二十一、$match
21.1 认识
$match
对输入文档进行筛选, 筛选文档流以仅允许匹配的文档将未修改的文档传入下一管道阶段。$match
使用标准 MongoDB
查询。对于每个输入文档,输出一个文档(一个匹配项)或零个文档(无匹配项)。应该尽量在聚合管道的开始阶段应用 $match
,这样可以减少后续阶段中需要处理的文档数量, 以优化聚合操作的性能。
21.2 语法
{ $match: { <query predicate> } }
-
匹配查询:
{ <field>: 指定值 }
-
比较操作符:
-
{ <field>: { $lt: <value> } }
-
{ <field>: { $gt: <value> } }
-
{ <field>: { $eq: <value> } }
-
{ <field>: { $ne: <value> } }
-
{ <field>: { $in: [<value1>, <value2>, ……] }}
-
{ <field>: { $nin: [<value1>, <value2>, ……] }}
-
{ <field>: { $lte: <value> } }
-
{ <field>: { $gte: <value> } }
-
-
逻辑操作符:
-
{ <field>: { $not: { <operator-expression> }}}
-
{ $or: [ {<expression>}, {<expression>}, ……]}
-
{ $nor: [ {<expression>}, {<expression>}, ……]}
-
{ $and: [ {<expression>}, {<expression>}, ……]}
或者{ <expression>, <expression>, …… }
-
-
字段操作符
-
{ <field>: { $exists: <boolean> }}
-
{ <field>: { $type: [<BSON type1>, <BSON type2>, ……]}}
-
-
数组操作符:
-
{ <field>: { $all: [ <value1>, <value2> …… ]}}
-
{ <field>: { $elemMatch: { <query1>, <query2>, ……}}}
-
-
运算操作符
{ <field>: { $regex: /pattern/, $options: <options> } }
21.3 用法
$match
对输入文档进行筛选
// 新增几个文档
db.user1.insertMany([ { name: { firstName: "alice", lastName: "wong" }, balance: 50}, { name: { firstName: "bob", lastName: "yang" }, balance: 20}])
// $match 对文档进行筛选
db.user1.aggregate([ { $match: { "name.firstName": { $eq: "alice" }} } ]);
db.user1.aggregate([ { $match: { $or: [ { balance: { $gt: 40, $lt: 80 }}, { "name.lastName": { $regex: /^y/ }}] } }]);
// 将 $match 管道的筛选结果传递给 $project 管道
db.user1.aggregate([ { $match: { $or: [ { balance: { $gt: 40, $lt: 80 }}, { "name.lastName": { $regex: /^y/ }}] } }, { $project: { _id: 0}}]);
二十二、$merge
22.1 认识
$merge
将 aggregation pipeline
的结果文档写入集合。该阶段可将结果(插入新文档、合并文档、替换文档、保留现有文档、操作失败、使用自定义更新管道处理文档)纳入输出集合。要使用 $merge
阶段,它必须是管道中的最后一个阶段。
22.2 语法
22.3 用法
二十三、$out
23.1 认识
$out
将 aggregation pipeline
的结果文档写入集合。要使用 $out
阶段,它必须是管道中的最后一个阶段。
23.2 语法
{ $out: "<output-collection>" }
{ $out: { db: "<output-db>", coll: "<output-collection>" } }
{ $out:
{ db: "<output-db>", coll: "<output-collection>",
timeseries: {
timeField: "<field-name>",
metaField: "<field-name>",
granularity: "seconds" || "minutes" || "hours" ,
}
}
}
23.3 用法
db.transactions.insertMany([ { symbol: "600519", qty: 100, price: 567.4, currency: "CNY" }, { symbol: "AMZN", qty: 1, price: 1377.5, currency: "USD" }, { symbol: "AAPL", qty: 2, price: 150.7, currency: "USD"} ]);
// 第一次, output 集合不存在
db.transactions.aggregate([ { $group: { _id: "$currency", symbols: { $push: "$symbol" } } }, { $out: "output" } ]);
// 第二次, output 集合存在, 直接覆盖之前的集合
db.transactions.aggregate([ { $group:{ _id: "$symbol", totalNotional: { $sum: { $multiply: [ "$price", "$qty" ] } } } },{ $out: "output" } ]);
二十四、$planCacheStats
24.1 认识
$planCacheStats
返回集合的计划缓存信息。
24.2 语法
24.3 用法
二十五、$project
25.1 认识
$project
对输入文档再次投影,重塑流中的每个文档。可以用来灵活的控制输出文档的格式, 也可以用来剔除不相关的字段,以优化聚合管道操作的性能。例如添加新的字段或删除现有字段。对于每个输入文档,输出一个文档。$project
采用的文档可以指定包含字段、抑制 _id
字段、添加新字段以及重置现有字段的值。您也可以指定排除字段。
25.2 语法
{ $project: { <specification(s)> } }
-
<field>: <1 or true>
: 指定包含字段。非零整数也被视为true
。 -
_id: <0 or false>
: 指定抑制_id
字段。要有条件地排除字段,请改用REMOVE
变量。 -
<field>: <expression>
: 添加新字段或重置现有字段的值。如果表达式的计算结果为$REMOVE
,则在输出中排除该字段。 -
<field>: <0 or false>
: 指定排除某个字段。 要有条件地排除字段,请改用REMOVE
变量。如果指定排除_id
以外的字段,则不能使用任何其他$project
规范形式。此限制应用用于使用REMOVE
变量有条件地排除字段。
25.3 用法
$project
对输入文档再次投影
// 新增几个文档
db.user1.insertMany([ { name: { firstName: "alice", lastName: "wong" }, balance: 50}, { name: { firstName: "bob", lastName: "yang" }, balance: 20}])
// $project 重新投影
db.user1.aggregate([ { $project: { _id: 0, balance: 1, clientName: "$name.firstName", nameArray: ["$name.firstName", "$name.lastName"] } } ]);
二十六、$querySettings
26.1 认识
$querySettings
返回之前使用 setQuerySettings
添加的查询设置。
26.2 语法
26.3 用法
二十七、$queryStats
27.1 认识
$queryStats
返回已记录查询的运行时统计信息。
27.2 语法
27.3 用法
二十八、$redact
28.1 认识
$redact
根据文档中存储的信息来限制每个文档的内容,从而重塑流中的每个文档。结合了 $project
和 $match
的功能。可用于实现字段级别访问控制。对于每个输入文档,输出一个或零个文档。
28.2 语法
28.3 用法
二十九、$replaceRoot
29.1 认识
$replaceRoot
用指定的嵌入文档替换文档。该操作会替换输入文档中的所有现有字段,包括 _id
字段。指定嵌入在输入文档中的文档,以将嵌入的文档提升到顶层。
29.2 语法
29.3 用法
三十、$replaceWith
30.1 认识
$replaceWith
用指定的嵌入文档替换文档。该操作会替换输入文档中的所有现有字段,包括 _id
字段。指定嵌入在输入文档中的文档,以将嵌入的文档提升到顶层。
30.2 语法
30.3 用法
三十一、$sample
31.1 认识
$sample
从其输入中随机选择指定数量的文件。
31.2 语法
31.3 用法
三十二、$search
32.1 认识
$search
对 Atlas 集合中的一个或多个字段执行全文搜索。
32.2 语法
32.3 用法
三十三、$searchMeta
33.1 认识
$searchMeta
返回对 Atlas 集合进行 Atlas Search 查询时,得到的不同类型的元数据结果文档。
33.2 语法
33.3 用法
三十四、$set
34.1 认识
$set
为文档添加新字段。与 $project
类似,$set
重塑了流中的每个文档;具体来说,就是在输出文档中添加新字段,这些输出文档既包含输入文档中的现有字段,也包含新添加的字段。
34.2 语法
34.3 用法
三十五、$setWindowFields
35.1 认识
$setWindowFields
将文档分组到窗口中,并将一个或多个操作符应用于每个窗口中的文档。
35.2 语法
35.3 用法
三十六、$skip
36.1 认识
$skip
跳过前 n 个文档,其中 n 是指定的跳过编号,并将未修改的剩余文档传递到管道。对于每个输入文档,输出零个文档(对于前 n 个文档)或一个文档(如果在前 n 个文档之后)。
36.2 语法
36.3 用法
$skip
跳过管道内前 N
篇文档:
// 新增几个文档
db.user1.insertMany([ { name: { firstName: "alice", lastName: "wong" }, balance: 50}, { name: { firstName: "bob", lastName: "yang" }, balance: 20}])
// $skip 跳过管道内前 N 篇文档
db.user1.aggregate([ { $skip: 1} ]);
三十七、$sort
37.1 认识
$sort
按指定的排序键对文档流重新排序。仅顺序会改变,而文档则保持不变。对于每个输入文档,输出一个文档。如果对多个字段进行排序,则按从左到右的顺序进行排序。例如,在上面的表单中,文档首先按 <field1>
排序。然后,具有相同 <field1>
值的文档将按 <field2>
进一步排序。
37.2 语法
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
-
1
: 升序排序。 -
-1
: 降序排序。 -
{ $meta: "textScore" }
: 按计算的textScore
元数据降序排序顺序。
37.3 用法
$sort
对输入文档进行排序
db.user1.aggregate([ { $sort: { balance: 1, "name.lastName": -1 } } ]);
三十八、$sortByCount
38.1 认识
$sortByCount
根据指定表达式的值对传入文档进行分组,然后计算每个不同群组中的文档数量。
38.2 语法
38.3 用法
三十九、$unionWith
39.1 认识
$unionWith
执行两个集合的联合;即将两个集合的管道结果合并到一个结果集中。
39.2 语法
39.3 用法
四十、$unset
40.1 认识
$unset
从文档中删除/排除字段。
40.2 语法
40.3 用法
四十一、$unwind
41.1 认识
$unwind
对输入文档中的某一数组字段进行解构,以便为每个元素输出文档。每个输出文档均会将此数组替换为元素值。对于每个输入文档,输出 n
个文档,其中 n
为数组元素的数量,且对于空数组可为零。
41.2 语法
{
$unwind:
{
path: <field path>,
includeArrayIndex: <string>,
preserveNullAndEmptyArrays: <boolean>
}
}
-
path
: 数组字段的字段路径。如需指定字段路径,请在字段名称前加上美元符号 $,并用引号括起来。 -
includeArrayIndex
: 可选。新字段的名称,用于保存该元素的数组索引。名称不能以美元符号$
开头。 -
preserveNullAndEmptyArrays
: 可选。如果true
,如果path
为null
、缺失或空大量,$unwind
会输出文档。false
如果为path
,如果 为null
、缺失或空大量,则$unwind
不会输出文档。默认值为false
。
41.3 用法
$unwind
展开输入文档中的数组字段
db.user1.update({ "name.firstName": "alice"}, { $set: { currency: ["CNY", "USD"]}});
db.user1.update({ "name.firstName": "bob"}, { $set: { currency: ["GBP"]}});
db.user.insertMany([ { name: { firstName: "charlie", lastName: "gordon" }, balance: 100},{ name: { firstName: "david", lastName: "wu" }, balance: 200, currency: []}, { name: { firstName: "eddie", lastName: "kim" }, balance: 20, currency: null} ]);
// $unwind 展开输入文档中的数组字段, 将数组字段中的每个元素新建文档,新文档跟原文档一模一样, 唯一的区别是数组字段值变为每一个元素。
db.user1.aggregate([ { $unwind: { path: "$currency", includeArrayIndex: 'ccyIndex', preserveNullAndEmptyArrays: false } } ]);
// 结果如下:
[
{
_id: ObjectId('67bf93c73d5b2b20ce11cbca'),
name: { firstName: 'alice', lastName: 'wong' },
balance: 50,
currency: 'CNY',
ccyIndex: Long('0')
},
{
_id: ObjectId('67bf93c73d5b2b20ce11cbca'),
name: { firstName: 'alice', lastName: 'wong' },
balance: 50,
currency: 'USD',
ccyIndex: Long('1')
},
{
_id: ObjectId('67bf93c73d5b2b20ce11cbcb'),
name: { firstName: 'bob', lastName: 'yang' },
balance: 20,
currency: 'GBP',
ccyIndex: Long('0')
}
]
四十二、$vectorSearch
42.1 认识
$vectorSearch
对 Atlas 集合的指定字段中的向量执行 ANN 或 ENN 搜索。