MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似sql语句中的 count(*)。

aggregate() 方法

MongoDB中聚合的方法使用aggregate()。

语法

aggregate() 方法的基本语法格式如下所示:

>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

下表展示了一些聚合的表达式:

表达式 描述 实例
$sum 计算总和。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])
$avg 计算平均值 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
$min 获取集合中所有文档对应值得最小值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])
$max 获取集合中所有文档对应值得最大值。 db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])
$push 在结果文档中插入值到一个数组中。 db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}])
$addToSet 在结果文档中插入值到一个数组中,但不创建副本。 db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first 根据资源文档的排序获取第一个文档数据。 db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}])
$last 根据资源文档的排序获取最后一个文档数据 db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}])

管道的概念

管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。

MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。

表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。

这里我们介绍一下聚合框架中常用的几个操作:

  • $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
  • $match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
  • $limit:用来限制MongoDB聚合管道返回的文档数。
  • $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
  • $group:将集合中的文档分组,可用于统计结果。
  • $sort:将输入文档排序后输出。
  • $geoNear:输出接近某一地理位置的有序文档。

练习:

数据

> db.user.find()
{ "_id" : ObjectId("5ab8b9495a96a08a5b909000"), "name" : "qlq1", "age" : , "se
x" : "男" }
{ "_id" : ObjectId("5ab8b9535a96a08a5b909001"), "name" : "qlq2", "age" : , "se
x" : "男" }
{ "_id" : ObjectId("5ab8b9685a96a08a5b909002"), "name" : "qlq3", "age" : , "se
x" : "女" }
{ "_id" : ObjectId("5ab8b96e5a96a08a5b909003"), "name" : "qlq4", "age" : , "se
x" : "女" }

使用方法:使用管道过滤数据之后利用表达式对数据进行操作:

  • 测试分组管道与表达式:  $group   分组统计

1.按性别分组,并计算男女人数

db.user.aggregate([
{$group:{
_id:"$sex",
num:{$sum:}
}
}])

 

  解释:_id:"$sex"表示按sex属性分组;  $sum表示求和,如果是$sum:1就相当于count(*),一行记录算一个

2.按性别分组,计算年龄和:

db.user.aggregate([
{$group:{
_id:"$sex",
num:{$sum:"$age"}
}
}])

3.按性别分组,并拿到每个组的第一个年龄:

db.user.aggregate([
{$group:{
_id:"$sex",
num:{$first:"$age"}
}
}])

 4.先按性别分组,分完组之后将age属性映射到数组中:(相当于分完组之后查看同组的数据,mysql不能实现)

db.user.aggregate([
{$group:{
_id:"$sex",
num:{$push:"$age"}
}
}])

如果是将所有列都添加到数组中用  $push:$$ROOT

db.user.aggregate([
{$group:{
_id:"$sex",
num:{$push:"$$ROOT"}
}
}])

结果:

/* 1 */
{
"_id" : "女",
"num" : [
{
"_id" : ObjectId("5ab8b9685a96a08a5b909002"),
"name" : "qlq3",
"age" : 23.0,
"sex" : "女"
},
{
"_id" : ObjectId("5ab8b96e5a96a08a5b909003"),
"name" : "qlq4",
"age" : 24.0,
"sex" : "女"
}
]
} /* 2 */
{
"_id" : "男",
"num" : [
{
"_id" : ObjectId("5ab8b9495a96a08a5b909000"),
"name" : "qlq1",
"age" : 20.0,
"sex" : "男"
},
{
"_id" : ObjectId("5ab8b9535a96a08a5b909001"),
"name" : "qlq2",
"age" : 22.0,
"sex" : "男"
}
]
}
  • $match管道:   类似于find,只是find不能统计,现在是可以过滤并统计

1.查询年龄大学23小于等于50的(只是过滤)

db.user.aggregate([
{
$match:{
age:{$gt:,$lte:}
}
}
])

2.在上面过滤的基础上聚合(先过滤,再分组)

db.user.aggregate([
{
$match:{
age:{$gt:,$lte:},
}
},
{
$group:{
_id:"$sex",
num:{
$sum:
}
}
}
])
  • $project   修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。类似于find方法的第二个参数

1.查询年龄大学23小于等于50的,按性别分组并统计人数,并且只取人数列:

db.user.aggregate([
{
$match:{
age:{$gt:,$lte:},
}
},
{
$group:{
_id:"$sex",
num:{
$sum:
}
}
},
{
$project:{
_id:,
num:
}
}
])

解释:  $project:{_id:0,num:1}表示在结果中取num列,不取_id列。

  • $sort  排序。类似于sort方法,指定一列并指明排序方式

 1.查询年龄大于21小于等于35并且按性别分组之后两列都取,按总数降序排列

db.user.aggregate([
{
$match:{
age:{$gt:,$lte:},
}
},
{
$group:{
_id:"$sex",
num:{
$sum:
}
}
},
{
$project:{
_id:,
num:
}
},
{
$sort:{num:-}
}
])

  •  $skip  跳过几列:     $limit:取几列

例如:在上面排序例子的基础上先跳过1列,取1个值

db.user.aggregate([
{
$match:{
age:{$gt:,$lte:},
}
},
{
$group:{
_id:"$sex",
num:{
$sum:
}
}
},
{
$project:{
_id:,
num:
}
},
{
$sort:{num:-}
},
{
$skip:
},
{
$limit:
}
])

例如:在上面排序例子的基础上先取1列,再跳过1列  (取不到数据)

db.user.aggregate([
{
$match:{
age:{$gt:,$lte:},
}
},
{
$group:{
_id:"$sex",
num:{
$sum:
}
}
},
{
$project:{
_id:,
num:
}
},
{
$sort:{num:-}
},
{
$limit:
},
{
$skip:
}
])

  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。     将数组拆分成一个一个的数据 (相当于分组的逆操作)

构造数据:

> db.tshirt.insert({name:'t1',size:,size:["x","xxx","M"]})
WriteResult({ "nInserted" : })
> db.tshirt.find()
{ "_id" : ObjectId("5ab8c3ce807bacd3133efcf8"), "name" : "t1", "size" : [ "x", "
xxx", "M" ] }
>

例如;按size拆分数据

db.tshirt.aggregate([
{
$unwind:'$size'
}
])

对于特殊情况的处理:(非数组,不存在的列,为空数组,为null)

构造数据:

> db.tshirt.find()
{ "_id" : ObjectId("5ab8c5ea807bacd3133efcfd"), "name" : "t1", "price" : , "size" : [ "m", "xx", "l" ] }
{ "_id" : ObjectId("5ab8c5f2807bacd3133efcfe"), "name" : "t1", "price" : , "size" : [ ] }
{ "_id" : ObjectId("5ab8c608807bacd3133efcff"), "name" : "t3", "price" : , "size" : "3x" }
{ "_id" : ObjectId("5ab8c62e807bacd3133efd02"), "name" : "t3", "price" : }
{ "_id" : ObjectId("5ab8c746807bacd3133efd03"), "name" : "t3", "price" : , "size" : null }
>

 1.直接拆分:()

db.tshirt.aggregate([
{
$unwind:'$size'
}
])

结果:发现数据丢失(字段不存在的和属性值为null的数据丢失)

 2.拆分且防止数据丢失

db.tshirt.aggregate([
{
$unwind:{
path:"$size",
preserveNullAndEmptyArrays:true  #为true表示防止空数组和null丢失
}
}
])

例如:按价格进行分组之后将数据映射到数组中,并按此列拆分数据

db.tshirt.aggregate([
{
$group:{
_id:"$price",
docs:{
$push:"$$ROOT"
}
}
},
{
$project:{
_id:,
docs:
}
},
{
$unwind:{
path:"$docs",
preserveNullAndEmptyArrays:true
}
}
])

结果:

/* 1 */
{
"_id" : 93.0,
"docs" : {
"_id" : ObjectId("5ab8c608807bacd3133efcff"),
"name" : "t3",
"price" : 93.0,
"size" : "3x"
}
} /* 2 */
{
"_id" : 93.0,
"docs" : {
"_id" : ObjectId("5ab8c62e807bacd3133efd02"),
"name" : "t3",
"price" : 93.0
}
} /* 3 */
{
"_id" : 93.0,
"docs" : {
"_id" : ObjectId("5ab8c746807bacd3133efd03"),
"name" : "t3",
"price" : 93.0,
"size" : null
}
} /* 4 */
{
"_id" : 90.0,
"docs" : {
"_id" : ObjectId("5ab8c5ea807bacd3133efcfd"),
"name" : "t1",
"price" : 90.0,
"size" : [
"m",
"xx",
"l"
]
}
} /* 5 */
{
"_id" : 90.0,
"docs" : {
"_id" : ObjectId("5ab8c5f2807bacd3133efcfe"),
"name" : "t1",
"price" : 90.0,
"size" : []
}
}

MongoDB 聚合(管道与表达式)的更多相关文章

  1. MongoDB 聚合管道(Aggregation Pipeline)

    管道概念 POSIX多线程的使用方式中, 有一种很重要的方式-----流水线(亦称为"管道")方式,"数据元素"流串行地被一组线程按顺序执行.它的使用架构可参考 ...

  2. MongoDB基础教程系列--第七篇 MongoDB 聚合管道

    在讲解聚合管道(Aggregation Pipeline)之前,我们先介绍一下 MongoDB 的聚合功能,聚合操作主要用于对数据的批量处理,往往将记录按条件分组以后,然后再进行一系列操作,例如,求最 ...

  3. MongoDB聚合管道

    通过上一篇文章中,认识了MongoDB中四个聚合操作,提供基本功能的count.distinct和group,还有可以提供强大功能的mapReduce. 在MongoDB的2.2版本以后,聚合框架中多 ...

  4. mongodb聚合管道用法

    基本用法 db.collection.aggregate( [ { <stage> }, ... ] ) stage如下 名称 描述 $addFields 将新的字段添加到文档中,输出的文 ...

  5. MongoDB 聚合管道

     参见:http://www.cnblogs.com/liruihuan/p/6686570.html MongoDB 的聚合功能,聚合操作主要用于对数据的批量处理,往往将记录按条件分组以后,然后再进 ...

  6. MongoDB聚合管道(Aggregation Pipeline)

    参考聚合管道简介 聚合管道 聚合管道是基于数据处理管道模型的数据聚合框架.文档进入一个拥有多阶段(multi-stage)的管道,并被管道转换成一个聚合结果.最基本的管道阶段提供了跟查询操作类似的过滤 ...

  7. 【mongoDB查询进阶】聚合管道(三)--表达式操作符

    https://segmentfault.com/a/1190000010910985 管道操作符的分类 管道操作符可以分为三类: 阶段操作符(Stage Operators) 表达式操作符(Expr ...

  8. MongoDB 聚合管道(aggregate)

    1.aggregate() 方法 我们先插入一些测试数据 { "_id" : ObjectId("5abc960c684781cda6d38027"), &qu ...

  9. 【翻译】MongoDB指南/聚合——聚合管道

    [原文地址]https://docs.mongodb.com/manual/ 聚合 聚合操作处理数据记录并返回计算后的结果.聚合操作将多个文档分组,并能对已分组的数据执行一系列操作而返回单一结果.Mo ...

随机推荐

  1. Git初步

    在多人参与开发的项目中,版本控制工具是必须的,网上有很多不错的教程,能简单使用就ok了,粘几篇教程,方便学习 首先我们要了解一些基本的概念,此处简单描述一下 (1)集中式版本控制系统: CVS.SVN ...

  2. 「日常训练」「小专题·图论」 Frogger (1-1)

    题意 分析 变形的dijkstra. 分析题意之后补充. 代码 // Origin: // Theme: Graph Theory (Basic) // Date: 080518 // Author: ...

  3. python 网络编程(远程执行命令与粘包)

    远程执行命令 先来学习一个新模块 , 一会用到的.. 新模块: subprocess 执行系统命令 r = subprocess.Popen('ls',shell=True,stdout=subpro ...

  4. Spring实战第四章学习笔记————面向切面的Spring

    Spring实战第四章学习笔记----面向切面的Spring 什么是面向切面的编程 我们把影响应用多处的功能描述为横切关注点.比如安全就是一个横切关注点,应用中许多方法都会涉及安全规则.而切面可以帮我 ...

  5. LeetCode 19——删除链表的倒数第 N 个节点

    1. 题目 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. 示例: 给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后 ...

  6. spring-data-jpa 简单使用心得

    对于总是使用mybatis的我,突发奇想的想使用spring-data-jpa搭一个小环境,这几天处处碰壁,现总结如下: 环境采用springboot maven需要导入: <dependenc ...

  7. pta编程(1-8)

    知识点:本次编程运用到的格式 #include<stdio.h> int main(void) { printf(); return 0; } 过程:1-3.没什么问题,就是注意字符的输入 ...

  8. 全局 Ajax 事件处理器

    jQuery中将Ajax请求和响应分成了若干(5)个阶段 并且允许开发者在Ajax请求和响应的不同阶处理不同的逻辑, 这些方法用于注册事件处理器,用来处理页面上的任何 Ajax 请求,当某些事件触发后 ...

  9. 将CRUD封装到一个工具类中

    package org.zln.hibernate.utils; import org.hibernate.Session; import org.hibernate.SessionFactory; ...

  10. 前端工程师必须要知道的SEO技巧(2):制作比设计还要漂亮的代码(内容和语义化代码)实现下

    提醒自己:上一篇文章属于纯理论的文章,我自己有的部分之从网上摘抄的,我自己也是不理解的.或许过一段日子我就能全明白了.我自己还是喜欢实战,做几个例子就明白了. 怎么做让自己网页的标签来实现语义化,我直 ...