aggregate()
语 法 \color{red}{语法} 语法
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION);
数 据 \color{red}{数据} 数据
数据使用菜鸟教程的数据啦🤪🤪
/* 1 */
{
"_id" : ObjectId("5e86e29788e64443e448dfc0"),
"title" : "MongoDB Overview",
"description" : "MongoDB is no sql database",
"by_user" : "runoob.com",
"url" : "http://www.runoob.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}
/* 2 */
{
"_id" : ObjectId("5e86e2ad88e64443e448dfd2"),
"title" : "NoSQL Overview",
"description" : "No sql database is very fast",
"by_user" : "runoob.com",
"url" : "http://www.runoob.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 10
}
/* 3 */
{
"_id" : ObjectId("5e86e2bc88e64443e448dfd7"),
"title" : "Neo4j Overview",
"description" : "Neo4j is no sql database",
"by_user" : "Neo4j",
"url" : "http://www.neo4j.com",
"tags" : [
"neo4j",
"database",
"NoSQL"
],
"likes" : 750
}
管 道 操 作 符 \color{red}{管道操作符} 管道操作符
操作符 | 含义 |
---|---|
$group | 将collection中的document分组,可用于统计结果 |
$match | 过滤数据,只输出符合结果的文档 |
$project | 修改输入文档的结构(例如重命名,增加、删除字段,创建结算结果等) |
$sort | 将结果进行排序后输出 |
$limit | 限制管道输出的结果个数 |
$skip | 跳过制定数量的结果,并且返回剩下的结果 |
$unwind | 将数组类型的字段进行拆分 |
表 达 式 操 作 符 \color{red}{表达式操作符} 表达式操作符
操作符 | 含义 | 实例 |
---|---|---|
$sum | 计算总和,{$sum : 1}表示返回总和×1的值(即总和的数量),使用{$sum : '$制定字段' }也能直接获取制定字段的值的总和 | db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$sum : "$likes"}}}]) |
$avg | 平均值 | db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$avg : "$likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值 | db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$min : "$likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值 | db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$max : "$likes"}}}]) |
$push | 在结果文档中插入值到一个数组中 | db.collection.aggregate([{$group : {_id : "$by_user", url : {$push : "$url"}}}]) |
$addToSet | 在结果文档中插入值到一个数组中,但不创建副本 | db.collection.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据 | db.collection.aggregate([{$group : {_id : "$by_user", url : {$first : "$url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.collection.aggregate([{$group : {_id : "$by_user", url : {$last : "$url"}}}]) |
具 体 例 子 \color{skyblue}{具体例子} 具体例子
-
$group
-
简单阐述
//将document分组,用作统计结果 db.collection.aggregate([ // aggregate方法接收的是一个数组 { $group: { // _id字段表示要基于哪个字段来进行分组(即制定字段值相同的为一组) // $by_user表示要基于$by_user字段来进行分组 _id: '$by_user', // content_sum字段的值$sum: 1表示的是获取满足by_user字段相同的这一组的数量乘以后面给定的值(本例为1,那么就是同组的数量)。 content_sum: {$sum: 1} } } ])
-
具体案例
通过以上集合计算每个作者所写的文章数(通过字段
by_user
字段对数据进行分组,并计算by_user
字段相同值的总和),使用aggregate()
计算结果如下:router.get('/getInfo',async(req, res)=>{ let data=await Content.aggregate([ { $group:{ _id:'$by_user', content_sum:{$sum:1} } } ]) res.json({data}) })
-
-
$match
获取
likes
的值在50-200
之间的数据:router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([{ $match: { likes: { $gt: 50, $lte: 200 } } }, { $group: { _id: '$_id', content_sum: { $sum: 1 } } } ]) res.json({ data }) })
从图中可以看出
likes
的值在50-200
之间的数据只有1条,现在我们只知道这条数据的_id,如果想知道这条数据的具体信息时应该如何操作呢❓上面的表格中提到$project
修改输入文档的结构(例如重命名,增加、删除字段,创建结算结果等),所以一起来看看吧👇👇👇 -
$project
router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([ { $match: { likes: { $gt: 50, $lte: 200 } } }, { //以下的值可以写$+字段,也可以使用0 和1来表示,若要显示字段则为1,否则为0 //$project:{_id:'$_id',title:"$title",description:"$description",by_user:"$by_user",url:'$ulr',tags:'$tags',likes:'$likes'} $project:{_id:1,title:1,description:1,by_user:1,url:1,tags:1,likes:1} } ]) res.json({ data }) })
-
以上3个操作符的综合使用
如果想拿到所有
likes>=10
的document的by_user
字段可以把管道搭配起来用:router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([{ $match: { likes: { $gt: 10 } } }, // 注意$project与$group的顺序,换位置后数据为空 { $project: { _id: 0, //_id不显示 by_user: 1 //by_user显示 } }, { $group: { _id: null, gameName: { $push: '$by_user' } } } ]) res.json({ data }) })
-
$sort
-
根据
likes
进行降序排序router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([ { $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 } }, { $sort: { likes: -1 } }, ]) res.json({ data }) })
-
根据
likes
进行升序排序router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([ { $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 } }, { $sort: { likes: 1 } }, ]) res.json({ data }) })
-
-
$limit and $skip
router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([ { $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 } }, { $sort: { likes: 1 } }, { $skip:1 }, { $limit:1 } ]); res.json({ data }) })
-
$unwind
$unwind管道以document中的数组类型的字段进行拆分,每条包含数组中的一个值。
比如拆分
likes:10
这条数据,先来看看整体数据信息吧:{ "_id" : ObjectId("5e86e2ad88e64443e448dfd2"), "title" : "NoSQL Overview", "description" : "No sql database is very fast", "by_user" : "runoob.com", "url" : "http://www.runoob.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 10 }
在
tags
数组中有3条数据,所以拆分后会显示3条数据,看看具体实现吧:router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([ { $match: { likes: 10 } }, { $unwind:'$tags' }, { $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 } }, ]) res.json({ data }) })