db.COLLECTION_NAME.aggregate([{},...])
方法来构建和使用聚合管道
官网示例
db.orders.aggregate()
来操作$match
表示匹配status属性为A的数据,也就是说$match
是个管道过滤出所有status为A的数据,得到一个集合$group
表示根据cust_id属性进行分组,分完组后对属性amount进行求和,也就是说$group
也是一个管道,得到我们想要的数据,在这里的$sum
是求和的管道表达式管道操作符 | Description |
---|---|
$project | 增加、删除、重命名字段 |
$match | 条件匹配,只满足条件的文档才能进入下一阶段 |
$limit | 限制结果的数量 |
$skip | 跳过文档的数量 |
$sort | 条件排序 |
$group | 条件组合结果、统计 |
$lookup | 用以引入其它集合的数据(表关联查询) |
SQL和NOSQL对比
WHERE | $match |
GROUP BY | $group |
HAVING | $match |
SELECT | $project |
ORDER BY | $sort |
LIMIT | $limit |
SUM() | $sum |
COUNT() | $sum |
join | $lookup |
管道表达式
{$match:{status:"A"}}
,$match称为管道操作符,而status:"A"称为管道表达式,是管道操作符的操作数(Operand)。常用表达式操作符 | Description |
---|---|
$addToSet | 将文档指定字段的值去重 |
$max | 文档指定字段的最大值 |
$min | 文档指定字段的最小值 |
$sum | 文档指定字段求和 |
$avg | 文档指定字段求平均 |
$gt | 大于给定值 |
$lt | 小于给定值 |
$eq | 等于给定值 |
db.order.insert({"order_id":"1","uid":10,"trade_no":"111","all_price":100,"all_num":2})
db.order.insert({"order_id":"2","uid":7,"trade_no":"222","all_price":90,"all_num":2})
db.order.insert({"order_id":"3","uid":9,"trade_no":"333","all_price":20,"all_num":6})
db.order_item.insert({"order_id":"1","title":"商品鼠标1","price":50,num:1})
db.order_item.insert({"order_id":"1","title":"商品键盘2","price":50,num:1})
db.order_item.insert({"order_id":"1","title":"商品键盘3","price":0,num:1})
db.order_item.insert({"order_id":"2","title":"牛奶","price":50,num:1})
db.order_item.insert({"order_id":"2","title":"酸奶","price":40,num:1})
db.order_item.insert({"order_id":"3","title":"矿泉水","price":2,num:5})
db.order_item.insert({"order_id":"3","title":"毛巾","price":10,num:1})
# 查询
> db.order.find()
# 结果
{ "_id" : ObjectId("5e8081ec0d65769967186242"), "order_id" : "1", "uid" : 10, "trade_no" : "111", "all_price" : 100, "all_num" : 2 }
{ "_id" : ObjectId("5e8081ec0d65769967186243"), "order_id" : "2", "uid" : 7, "trade_no" : "222", "all_price" : 90, "all_num" : 2 }
{ "_id" : ObjectId("5e8081ec0d65769967186244"), "order_id" : "3", "uid" : 9, "trade_no" : "333", "all_price" : 20, "all_num" : 6 }
# 查询
> db.order_item.find()
# 结果
{ "_id" : ObjectId("5e8081ec0d65769967186245"), "order_id" : "1", "title" : "商品鼠标1", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5e8081ec0d65769967186246"), "order_id" : "1", "title" : "商品键盘2", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5e8081ec0d65769967186247"), "order_id" : "1", "title" : "商品键盘3", "price" : 0, "num" : 1 }
{ "_id" : ObjectId("5e8081ec0d65769967186248"), "order_id" : "2", "title" : "牛奶", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5e8081ec0d65769967186249"), "order_id" : "2", "title" : "酸奶", "price" : 40, "num" : 1 }
{ "_id" : ObjectId("5e8081ec0d6576996718624a"), "order_id" : "3", "title" : "矿泉水", "price" : 2, "num" : 5 }
{ "_id" : ObjectId("5e8081ed0d6576996718624b"), "order_id" : "3", "title" : "毛巾", "price" : 10, "num" : 1 }
# 查询
> db.order_item.find({"order_id":"1"})
# 结果
{ "_id" : ObjectId("5e8081ec0d65769967186245"), "order_id" : "1", "title" : "商品鼠标1", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5e8081ec0d65769967186246"), "order_id" : "1", "title" : "商品键盘2", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5e8081ec0d65769967186247"), "order_id" : "1", "title" : "商品键盘3", "price" : 0, "num" : 1 }
1 ) 关于 $project
修改文档的结构,可以用来重命名、增加或删除文档中的字段
要求查找order只返回文档中 trade_no和 all_price字段
我们之前使用的方式是
db.order.find({}, {"trade_no":1, "all_price":1})
输出结果是
> db.order.find({}, {"trade_no":1, "all_price":1})
{ "_id" : ObjectId("5e8081ec0d65769967186242"), "trade_no" : "111", "all_price" : 100 }
{ "_id" : ObjectId("5e8081ec0d65769967186243"), "trade_no" : "222", "all_price" : 90 }
{ "_id" : ObjectId("5e8081ec0d65769967186244"), "trade_no" : "333", "all_price" : 20 }
现在我们使用管道的方式
db.order.aggregate([
{
$project:{"trade_no":1, "all_price":1 }
}
])
输出显示
# 这里筛选的数据,只显示order表中trade_no和all_price属性的数据
> db.order.aggregate([
{
$project:{"trade_no":1, "all_price":1 }
}
])
# 以下是查询结果
{ "_id" : ObjectId("5e8081ec0d65769967186242"), "trade_no" : "111", "all_price" : 100 }
{ "_id" : ObjectId("5e8081ec0d65769967186243"), "trade_no" : "222", "all_price" : 90 }
{ "_id" : ObjectId("5e8081ec0d65769967186244"), "trade_no" : "333", "all_price" : 20 }
2 ) 关于 $match
db.order.aggregate([
{
$project:{"trade_no":1, "all_price":1 }
},
{
$match:{"all_price":{$gte:90}}
}
])
# 过滤只显示两个属性,并查询all_price大于等于90的数据
> db.order.aggregate([
{
$project:{"trade_no":1, "all_price":1 }
},
{
$match:{"all_price":{$gte:90}}
}
])
# 查询结果如下
{ "_id" : ObjectId("5e8081ec0d65769967186242"), "trade_no" : "111", "all_price" : 100 }
{ "_id" : ObjectId("5e8081ec0d65769967186243"), "trade_no" : "222", "all_price" : 90 }
3 ) 关于 $group
将集合中的文档进行分组,可用于统计结果
统计每个订单的订单数量,按照订单号分组
db.order_item.aggregate(
[
{
$group: {_id: "$order_id", total: {$sum: "$num"}}
}
]
)
这里是按照order_id属性进行分组,并统计num属性的总和存放到新的total属性中
务必注意这里$num两侧的引号要带上,单双引号都可以
# 查询
db.order_item.aggregate(
[
{
$group: {_id: "$order_id", total: {$sum: "$num"}}
}
]
)
# 结果
{ "_id" : "2", "total" : 2 }
{ "_id" : "3", "total" : 6 }
{ "_id" : "1", "total" : 3 }
5 ) 关于 $sort
将集合中的文档进行排序
db.order.aggregate([
{
$project:{"trade_no":1, "all_price":1 }
},
{
$match:{"all_price":{$gte:90}}
},
{
$sort:{"all_price":-1}
}
])
这里$sort:{"all_price":-1}
-1 表示降序,1 表示升序,注意没有0这个选项
# 查询
db.order.aggregate([
{
$project:{"trade_no":1, "all_price":1 }
},
{
$match:{"all_price":{$gte:90}}
},
{
$sort:{"all_price":-1}
}
])
# 结果
{ "_id" : ObjectId("5e8081ec0d65769967186242"), "trade_no" : "111", "all_price" : 100 }
{ "_id" : ObjectId("5e8081ec0d65769967186243"), "trade_no" : "222", "all_price" : 90 }
6 ) 关于 $limit
db.order.aggregate([
{
$project:{"trade_no":1, "all_price":1 }
},
{
$match:{"all_price":{$gte:90}}
},
{
$sort:{"all_price":-1}
},
{
$limit:1
}
])
# 查询
db.order.aggregate([
{
$project:{"trade_no":1, "all_price":1 }
},
{
$match:{"all_price":{$gte:90}}
},
{
$sort:{"all_price":-1}
},
{
$limit:1
}
])
# 结果
{ "_id" : ObjectId("5e8081ec0d65769967186242"), "trade_no" : "111", "all_price" : 100 }
7 ) 关于 $skip
用于跳过几条数据进行查找
db.order.aggregate([
{
$project:{"trade_no":1, "all_price":1 }
},
{
$match:{"all_price":{$gte:90}}
},
{
$sort:{"all_price":-1}
},
{
$skip:1
}
])
原本测试数据可以查到2条数据,这里跳过第1条,只查到了第1条
# 查询
db.order.aggregate([
{
$project:{"trade_no":1, "all_price":1 }
},
{
$match:{"all_price":{$gte:90}}
},
{
$sort:{"all_price":-1}
},
{
$skip:1
}
])
# 结果
{ "_id" : ObjectId("5e8081ec0d65769967186243"), "trade_no" : "222", "all_price" : 90 }
通常结合$limit来进行数据分页,此处不再演示
8 ) $lookup 表关联
// eg1. 简单的关联
// 这里order集合需要关联order_item集合
// 通过order集合中的order_id属性和order_item集合中的order_id属性进行关联
// as表示将查询完的数据放入items里面:格式是主表order结构下的items属性存放关联数据
db.order.aggregate([
{
$lookup:
{
from: "order_item", // 关联的order_item集合
localField: "order_id", // 这里是order集合的字段
foreignField: "order_id", // 这里是order_item集合中的字段
as: "items" // 将查询出的数据挂载到items字段上
}
}
])
// eg2. 查询后对数据进行相关筛选
db.order.aggregate([
{
$lookup:
{
from: "order_item",
localField: "order_id",
foreignField: "order_id",
as: "items"
}
},
{
$match:{"all_price":{$gte:90}}
}
])
// eg3. 查询后对数据进行相关筛选
db.order.aggregate([
{
$lookup:
{
from: "order_item",
localField: "order_id",
foreignField: "order_id",
as: "items"
}
},
{
$project:{"trade_no":1, "all_price":1, "items":1 }
},
{
$match:{"all_price":{$gte:90}}
},
{
$sort:{"all_price":-1}
}
])