您的位置:首页 > 数据库 > Mongodb

MongoDB(6)数据聚合 & 管道操作

2018-02-22 01:55 537 查看

MongoDB 入门专栏

http://blog.csdn.net/column/details/19681.html


管道操作

mongodb 的数据聚合过程通常会配合管道操作,mongodb 的管道操作概念类似于 LInux 中的管道概念,mongodb 的聚合管道将 mongodb 文档在一个管道处理完毕后将结果传递给下一个管道处理,管道操作是可以以此重复的;
mongodb 管道使用 aggregte() 方法,使用管道表达式表示一个管道过程,表达式是无状态的,只能计算当前聚合管道的文档,不能处理其他文档,以下是常用的几种管道操作表达式:
聚合操作使用 aggregate() 函数,该函数原型为:db.collection_name.aggregate(<opeation>)其中 opeation 参数常用的表达式:
表达式说明
$project修改输入文档的结构,可以用于重命名、增加/删除域、创建计算结果、嵌套文档;
$match用于过滤数据,只输出符合条件的文档,$match 使用MongoDB的标准查询操作;
$limit用来限制MongoDB聚合管道返回的文档数;
$skip在聚合管道中跳过指定数量的文档,并返回余下的文档;
$count显示当前管道的文档数量
$size显示一个键(该键为数组类型)的数组长度;
$unwind将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值;
$group将集合中的文档分组,可用于统计结果;
$sort将输入文档排序后输出;
$geoNear输出接近某一地理位置的有序文档;
关于管道完整表达式列表的用法,参见:https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/
示例使用:以下为示例使用集合 blog 的文档结构:
 
{
  _id: ObjectId("5a88f21ac05302a3b998abb9"),
  title: 'MongoDB Overview',
  description: 'MongoDB is no sql database',
  author: 'assad',
  url: 'http://blog.assad.artcile/1',
  tags: ['mongodb', 'database', 'NoSQL'],
  likes: 100
},
{
  _id: ObjectId("5a88f278c05302a3b998abba"),
  title: 'NoSQL Overview',
  description: 'No sql database is very fast',
  author: 'Tim',
  url: 'http://blog.assad.artcile/34',
  tags: ['mongodb', 'database', 'NoSQL'],
  likes: 233
},
{
  _id: ObjectId("5a88f299c05302a3b998abbb"),
  title: 'SqlLite Overview',
  description: 'SqlLite is no sql database',
  author: 'assad',
  url: 'http://blog.assad.artcile/213',
  tags: ['SqlLite', 'database', 'NoSQL'],
  likes: 666
}

示例: 
# $project 示例:只显示 blog 集合的 title,author,likes 字段
> db.blog.aggregate(
...     [ {$project:{_id:0,title:1,author:1,likes:1}} ]
... )
{ "author" : "assad", "likes" : 100, "title" : "article_title" }
{ "author" : "Tim", "likes" : 233, "title" : "article_title" }
{ "author" : "assad", "likes" : 666, "title" : "article_title" }
# $count 示例:显示 blog 集合中 likes>100, likes<500 的文档的数量
> db.blog.aggregate([
... { $match:{likes:{$gt:100,$lt:500}} },
... { $count:"result" }
... ])
{ "result" : 1 }
# 综合示例:显示 blog 集合中每一条文档的 tages 总数
> db.blog.aggregate([
...    { $project:{_id:0,title:1,tages_count:{$size:"$tags"}} }
...])
{ "title" : "MongoDB Overview", "tages_count" : 3 }
{ "title" : "NoSQL Overview", "tages_count" : 3 }
{ "title" : "SqlLite Overview", "tages_count" : 3 }
# 综合示例:显示 blog 集合中 author="assad", likes>=100, likes<=800 的文档,按 likes 正序排序,只显示前 5 个文档,只显示 title,author,likes 字段
> db.blog.aggregate( [
...  { $project:{title:1,author:1,likes:1} },
...  { $match:{author:"assad",likes:{$gte:100,$lte:800}} },
...  { $limit:5 },
...  { $sort:{likes:1} }
... ]}
{ "_id" : ObjectId("5a88f21ac05302a3b998abb9"), "title" : "MongoDB Overview", "author" : "assad", "likes" : 100 }
{ "_id" : ObjectId("5a88f299c05302a3b998abbb"), "title" : "SqlLite Overview", "author" : "assad", "likes" : 666 }
# 综合示例:显示 blog 集合中 tags 键数组中各个值出现次数的统计
> db.blog.aggregate([
...    { $unwind:"$tags" },
...    { $group:{_id:"$tags",count:{$sum:1}}}
... ])
{ "_id" : "SqlLite", "count" : 1 }
{ "_id" : "NoSQL", "count" : 3 }
{ "_id" : "database", "count" : 3 }
{ "_id" : "mongodb", "count" : 2 }


$group 分组表达式

在 aggregate() 方法中使用 $group 表达式进行分组操作,类似于 SQL 中的 group by 子句,$group 常用的聚合表达式如下:
表达式说明
$sum计算总和;
$avg计算平均值;
$max获取文档对应键值的最大值上限;
$min获取文档对应键值的最小值;
$first根据文档的排序获取第一个文档;
$last根据文档的排序获取最后一个文档;
$push在结果文档中插入一个数组;
$addToSet在结果文档中插入一个数组,但是不创建副本;
示例:演示 $sum 
# 显示每一个 author 各自的 likes 总数
> db.blog.aggregate(
...    [ {$group:{_id:"$author",likes_count:{$sum:"$likes"} }} ]
...)
{ "_id" : "Tim", "likes_count" : 233 }
{ "_id" : "assad", "likes_count" : 766 }
# 显示所有文档的 likes 总数
> db.blog.aggregate(
...    [ {$group:{_id:null, likes_count:{$sum:"$likes"} }} ]
...)
{ "_id" : null, "likes_count" : 999 }
演示 $avg
 
# 显示各个 author 的 likes 平均数
> db.blog.aggregate(
...    [ {$group:{_id:"$author",likes_avg:{$avg:"$likes"} }} ]
...)
{ "_id" : "Tim", "likes_avg" : 233 }
{ "_id" : "assad", "likes_avg" : 383 }
# 显示所有文档 likes 的平均数
> db.blog.aggregate(
...    [ {$group:{_id:null, likes_avg:{$avg:"$likes"} }} ]
...)
{ "_id" : null, "likes_avg" : 333 }
演示 $min,$max
 
# 显示每一个 author 的 likes 最小值记录
> db.blog.aggregate(
...     [ {$group:{_id:"$author",likes_min:{$min:"$likes"} }} ]
... )
{ "_id" : "Tim", "likes_min" : 233 }
{ "_id" : "assad", "likes_min" : 100 }
# 显示所有文档记录中 likes 最小的记录
> db.blog.aggregate(
...     [ {$group:{_id:null, likes_min:{$min:"$likes"} }} ]
... )
{ "_id" : null, "likes_min" : 100 }
# 显示所有文档记录中 likes 最大的记录
> db.blog.aggregate(
...     [ {$group:{_id:null, likes_max:{$max:"$likes"} }} ]
... )
{ "_id" : null, "likes_max" : 666 }
演示 $push
 
# 显示各个 author 的 article title 和 likes 列表
> db.blog.aggregate(
...     [ {$group:{_id:"$author",article_like:{$push:{title:"$title",likes:"$likes"}}}} ]
... )
{ "_id" : "Tim", "article_like" : [ { "title" : "NoSQL Overview", "likes" : 233 } ] }
{ "_id" : "assad", "article_like" : [ { "title" : "MongoDB Overview", "likes" : 100 }, { "article" : "SqlLite Overview", "likes" : 666 } ] }


按时间分组聚合对于时间,按年月日,小时分钟秒进行分组聚合,可以使用以下表达式获取时间参数:$dayOfYear: 返回该日期是这一年的第几天(全年 366 天)。

$dayOfMonth: 返回该日期是这一个月的第几天(1到31)。

$dayOfWeek: 返回的是这个周的星期几(1:星期日,7:星期六)。

$year: 返回该日期的年份部分。

$month: 返回该日期的月份部分( 1 到 12)。

$week: 返回该日期是所在年的第几个星期( 0 到 53)。

$hour: 返回该日期的小时部分。

$minute: 返回该日期的分钟部分。

$second: 返回该日期的秒部分(以0到59之间的数字形式返回日期的第二部分,但可以是60来计算闰秒)。

$millisecond:返回该日期的毫秒部分( 0 到 999)。

$dateToString: { $dateToString: { format: , date: } }。

以下是示例用的 loginLog 集合内容:
 
{
       "_id" : ObjectId("5a8969f54a7c036151cce245"),
       "ip" : "25.12.4.42",
       "date" : ISODate("2018-02-16T09:33:12Z")
}
{
       "_id" : ObjectId("5a896a164a7c036151cce246"),
       "ip" : "126:123:11:1",
       "date" : ISODate("2018-02-17T10:20:00Z")
}
{
       "_id" : ObjectId("5a896a2c4a7c036151cce247"),
       "ip" : "23.88.44.22",
       "date" : ISODate("2018-01-20T20:30:00Z")
}
{
       "_id" : ObjectId("5a896a4a4a7c036151cce248"),
       "ip" : "55.78.22.123",
       "date" : ISODate("2018-02-19T21:59:20Z")
}
>
示例:
 
# 统计每个月分组的文档总数
> db.loginLog.aggregate([
...     { $group:{_id:{$month:"$date"},log_count:{$sum:1}} }
... ])
{ "_id" : 1, "log_count" : 1 }
{ "_id" : 2, "log_count" : 3 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: