目前为止,我们已经介绍了一部分聚合管道中的管道参数:
$match:文档过滤
$group:文档分组,并介绍了分组中的常用操作:$addToSet,$avg,$sum,$min,$max等。
$addFields:添加字段,等效于$set
$unset:移除字段
$project:字段投影
如果需要进一步了解可以参考:
MongoDB 聚合管道的文档筛选及分组统计https://blog.csdn.net/m1729339749/article/details/130034658MongoDB 聚合管道的字段投影https://blog.csdn.net/m1729339749/article/details/130055110这篇我们主要介绍使用聚合管道实现文档操作(排序、跳过、获取、随机抽取、分解)、集合操作(合并集合管道):
初始化零食数据
db.goods.insertMany([
{ "_id": 1, name: "薯片", size: "S", quantity: 10, price: 8, expirationTime: ISODate( "2023-08-08T00:00:00Z" ) },
{ "_id": 2, name: "薯片", size: "L", quantity: 8, price: 12, expirationTime: ISODate( "2023-08-08T00:00:00Z" ) },
{ "_id": 3, name: "牛肉干", size: "L", quantity: 5, price: 30, expirationTime: ISODate( "2023-10-10T00:00:00Z" ) },
{ "_id": 4, name: "可口可乐", size: "S", quantity: 10, price: 3, expirationTime: ISODate( "2025-01-06T00:00:00Z" ) },
{ "_id": 5, name: "可口可乐", size: "L", quantity: 6, price: 10, expirationTime: ISODate( "2025-01-06T00:00:00Z" ) },
{ "_id": 6, name: "旺仔牛奶", size: "L", quantity: 10, price: 5, expirationTime: ISODate( "2023-08-10T00:00:00Z" )}
])
初始化测试数据
db.test.insertMany(
[
{ "_id" : "1001", "name" : "张三", "fruits" : [ "apple", "orange" ] },
{ "_id" : "1002", "name" : "李四", "fruits" : [ "banana", "apple" ] },
{ "_id" : "1003", "name" : "王五", "fruits" : [ "banana", "apple", "orange" ] }
]
);
语法:{ $sort: {
将文档按照指定字段排序
其中,
语法中使用多个排序字段的原因是比较排序时当第一个字段对应的值相等时则使用第二个字段对应的值进行比较排序,依次类推。
例子1:按照零食的价格进行正序排序
db.goods.aggregate([
{
$sort: { "price": 1 }
}
])
聚合查询的结果:
{ "_id" : 4, "name" : "可口可乐", "size" : "S", "quantity" : 10, "price" : 3, "expirationTime" : ISODate("2025-01-06T00:00:00Z") }
{ "_id" : 6, "name" : "旺仔牛奶", "size" : "L", "quantity" : 10, "price" : 5, "expirationTime" : ISODate("2023-08-10T00:00:00Z") }
{ "_id" : 1, "name" : "薯片", "size" : "S", "quantity" : 10, "price" : 8, "expirationTime" : ISODate("2023-08-08T00:00:00Z") }
{ "_id" : 5, "name" : "可口可乐", "size" : "L", "quantity" : 6, "price" : 10, "expirationTime" : ISODate("2025-01-06T00:00:00Z") }
{ "_id" : 2, "name" : "薯片", "size" : "L", "quantity" : 8, "price" : 12, "expirationTime" : ISODate("2023-08-08T00:00:00Z") }
{ "_id" : 3, "name" : "牛肉干", "size" : "L", "quantity" : 5, "price" : 30, "expirationTime" : ISODate("2023-10-10T00:00:00Z") }
语法:{ $skip:
跳过N条文档,
例子:按照零食的价格进行正序排序,跳过两条零食
db.goods.aggregate([
{
$sort: { "price": 1 },
},
{
$skip: 2
}
])
聚合查询的结果:
{ "_id" : 1, "name" : "薯片", "size" : "S", "quantity" : 10, "price" : 8, "expirationTime" : ISODate("2023-08-08T00:00:00Z") }
{ "_id" : 5, "name" : "可口可乐", "size" : "L", "quantity" : 6, "price" : 10, "expirationTime" : ISODate("2025-01-06T00:00:00Z") }
{ "_id" : 2, "name" : "薯片", "size" : "L", "quantity" : 8, "price" : 12, "expirationTime" : ISODate("2023-08-08T00:00:00Z") }
{ "_id" : 3, "name" : "牛肉干", "size" : "L", "quantity" : 5, "price" : 30, "expirationTime" : ISODate("2023-10-10T00:00:00Z") }
语法:{ $limit:
获取N条文档,
例子:按照零食的价格进行正序排序,跳过两条零食后,获取两条零食
db.goods.aggregate([
{
$sort: { "price": 1 },
},
{
$skip: 2
},
{
$limit: 2
}
])
聚合查询的结果:
{ "_id" : 1, "name" : "薯片", "size" : "S", "quantity" : 10, "price" : 8, "expirationTime" : ISODate("2023-08-08T00:00:00Z") }
{ "_id" : 5, "name" : "可口可乐", "size" : "L", "quantity" : 6, "price" : 10, "expirationTime" : ISODate("2025-01-06T00:00:00Z") }
语法:{ $sample: { size:
从所有文档中随机查询N条文档,N是正整数;
例子:从所有零食中随机抽取2种零食
db.goods.aggregate([
{
"$project": {
"_id": 0,
"name": 1,
"size": {
$cond: {
if: { $eq: [ "S", "$size" ] },
then: "小包装",
else: "大包装"
}
}
}
},
{
"$sample": { size: 2 }
}
])
解释一下给出的聚合查询语句:
(1) 使用$project对所有的零食进行字段映射,只保留名称和型号两个字段
(2) 随机查询两条文档
执行聚合查询后会随机查询两条文档数据:
{ "name" : "可口可乐", "size" : "小包装" }
{ "name" : "牛肉干", "size" : "大包装" }
【注意】
(1) 随机查询的文档数据不会重复
(2) 如果随机查询的文档数(N)大于文档的总数(M),则只能返回M条文档
语法:{ $unwind:
解开数组字段的值,把数组中的每个元素构造成一个文档
例子:获取test集合中的fruits字段分解后的文档
db.test.aggregate([
{
$unwind: "$fruits"
}
])
聚合查询的结果:
{ "_id" : "1001", "name" : "张三", "fruits" : "apple" }
{ "_id" : "1001", "name" : "张三", "fruits" : "orange" }
{ "_id" : "1002", "name" : "李四", "fruits" : "banana" }
{ "_id" : "1002", "name" : "李四", "fruits" : "apple" }
{ "_id" : "1003", "name" : "王五", "fruits" : "banana" }
{ "_id" : "1003", "name" : "王五", "fruits" : "apple" }
{ "_id" : "1003", "name" : "王五", "fruits" : "orange" }
语法:{ $unionWith: { coll: "
合并两个集合的管道
[
例子:合并零食数据与test集合中的数据
合并两个集合管道
db.goods.aggregate([
{
$project: { "name": 1, "_id": 0 }
},
{
$unionWith: {
coll: "test",
pipeline: [
{
$project: { "name": 1, "_id": 0 }
}
]
}
}
])
我们对聚合查询进行一下解释:
(1) 使用$project 对goods集合中的文档进行投影,投影后只保留了name字段
(2) 使用$project 对test集合中的文档进行投影,投影后只保留了name字段
(3) 使用$unionWith 对两个集合的管道进行合并
聚合查询的结果:
{ "name" : "薯片" }
{ "name" : "薯片" }
{ "name" : "牛肉干" }
{ "name" : "可口可乐" }
{ "name" : "可口可乐" }
{ "name" : "旺仔牛奶" }
{ "name" : "张三" }
{ "name" : "李四" }
{ "name" : "王五" }