https://segmentfault.com/a/1190000010826809

什么是管道操作符(Aggregation Pipeline Operators)

mongoDB有4类操作符用于文档的操作,例如find查询里面会用到的$gte,$in等。操作符以$开头,分为查询操作符,更新操作符,管道操作符,查询修饰符4大类。其中管道操作符是用于聚合管道中的操作符。

管道操作符的分类

管道操作符可以分为三类:

  1. 阶段操作符(Stage Operators)
  2. 表达式操作符(Expression Operators)
  3. 累加器(Accumulators)
阶段操作符(Stage Operators)

阶段操作符是使用于db.collection.aggregate方法里面,数组参数中的第一层。

db.collection.aggregate( [ { 阶段操作符:表述 }, { 阶段操作符:表述 }, ... ] )
表达式操作符(Expression Operators)

表达式操作符主要用于在管道中构建表达式时使用,使用类似于函数那样需要参数,主要用于$project操作符中,用于构建表达式,使用方法一般如下:

方法1:

{ <operator>: [ <argument1>, <argument2> ... ] }

方法2:

{ <operator>: <argument> }
累加器(Accumulators)

累加器本来只能使用与$groud下,但是版本3.2或以上,部分累加器还能使用于$project。当在$group中使用时,累加器是针对每个分组使用的;当在$project中使用时,累加器则是针对每个字面量起作用,具体用法下一篇文章阐述。

常用阶段操作符

操作符 简述
$match 匹配操作符,用于对文档集合进行筛选
$project 投射操作符,用于重构每一个文档的字段,可以提取字段,重命名字段,甚至可以对原有字段进行操作后新增字段
$sort 排序操作符,用于根据一个或多个字段对文档进行排序
$limit 限制操作符,用于限制返回文档的数量
$skip 跳过操作符,用于跳过指定数量的文档
$count 统计操作符,用于统计文档的数量
$group 分组操作符,用于对文档集合进行分组
$unwind 拆分操作符,用于将数组中的每一个值拆分为单独的文档
$lookup 连接操作符,用于连接同一个数据库中另一个集合,并获取指定的文档,类似于populate

阶段操作符详解

假设有一个保存用户的集合Users,一个文章的集合Articles,数据大致如下:
users:

[
{ name: 'John', age: , sex: male, city: guangzhou, _id: , ...},
{ name: 'Rose', age: , sex: female, city: beijing, _id: , ...},
{ name: 'Jack', age: , sex: male, city: guangzhou, _id: , ...},
{ name: 'Allen', age: , sex: female, city: beijing, _id: , ...},
{ name: 'Cruz', age: , sex: male, city: guangzhou, _id: , ...},
{ name: 'Peter', age: , sex: male, city: guangzhou, _id: , ...},
{ name: 'Kelly', age: , sex: female, city: shanghai, _id: , ...},
...
]

articles:

[
{ title: 'this is article A', author: 'John', _id: , ... },
{ title: 'this is article B', author: 'Jack', _id: , ... },
{ title: 'this is article C', author: 'Rose', _id: , ... },
{ title: 'this is article D', author: 'John', _id: , ... },
{ title: 'this is article E', author: 'John', _id: , ... },
...
]

$match 匹配操作符

说明:
用于重构每一个文档的字段,可以提取字段,重命名字段,甚至可以对原有字段进行操作后新增字段
用法:
{ $match: { <query> } }
示例:
  • 查询用户年龄是18岁的用户
db.users.aggregate([{ $match : { age : "" } }]);

$project 投射操作符

说明:
用于对文档集合进行筛选
用法:
{ $project: { <specification(s)> } }

specification的规则

规则 描述
<字段名>: 1 or true 选择需要返回什么字段
_id: 0 or false 不返回_id(默认返回)
<字段名>: 表达式 使用表达式,可以用于重命名字段,或对其值进行操作,或新增字段
<字段名>: 0 or false 选择需要不返回什么字段,注意:当使用这种用法时,就不要用上面的方法
示例1:
  • 用户集合投射用户姓名
  • 不返回_id
db.users.aggregate([{ $project : { name:  } }]);
示例2:
  • 将_id重命名为userId
  • 不返回_id_
db.users.aggregate([{ $project : { ueserId: '$_id', _id:  } }]);
示例3:
  • 返回新字段username,并使用表达式让它的值为name的大写。
db.users.aggregate([
{
$project : {
name: ,
username: { $toUpper: '$name' },
_id:
}
}
]);

关于管道表达式:最简单的“$project”表达式是包含和排除字段(如: { name: 1 }),以及字段名称$fieldname(如: { userId: '$_id' })。除此以外,还可以使用表达式操作符(如: $toUpper)构成更丰富的表达式,将多个字面量和变量组合在一起使用,得到更多有意思的值,更多表达式操作符的说明及使用在另外的篇章中详细阐述。

$sort 排序操作符

说明:
用于根据一个或多个字段对文档进行排序
用法:
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
示例:
  • users集合按照年龄age从低到高排序
db.users.aggregate([{ $sort : { age:  } }]);

$limit 限制操作符

说明:
用于限制返回文档的数量
用法:
{ $limit: <positive integer> }
示例:
  • 返回5篇article
db.articles.aggregate({ $limit :  });

$skip 跳过操作符

说明:
用于跳过指定数量的文档
用法:
{ $skip: <positive integer> }
示例:
  • 跳过1个文档
db.users.aggregate([{ $skip :  }]);

$count 统计操作符

说明:
用于统计文档的数量
用法:
{ $count: <string> }
string是统计之后输出统计结果的字段名
示例:
  • 统计文章的总数,以totalArticle返回
db.articles.aggregate([{ totalArticle :  }]);

$group 分组操作符

说明:
用于对文档集合进行分组
用法:
{ $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ... } }
_id是必须的,用作分组的依据条件
示例:
  • 将用户(users)按性别(sex)分组
db.users.aggregate([{ $group : { _id: '$sex' } }]);

返回结果:

[
{ _id: 'male' },
{ _id: 'female' }
]
进阶示例:
  • 将用户(users)按性别(sex)分组
  • 分组后使用计算各自性别的平均年龄
  • 统计不同的性别的人数,并以count返回
db.users.aggregate([
{
$group : {
_id: '$sex',
avgAge: { $avg: '$age' },
conut: { $sum: }
}
}
]);

返回结果:

[
{ _id: 'male', avgAge: <男性平均年龄>, count: <男性人数> },
{ _id: 'female', avgAge: <女性平均年龄>, count: <女性人数> }
]
此处用到的表达式 { $avg: '$age' } 用于求平均年龄,$avg是求均值的操作符,$sum用于汇总, 都只能在$group中使用的累加器,mongoDB3.2以上版本则还可以在$project中使用,详细会在另外的篇章中阐述。

$unwind 拆分操作符

说明:
用于将数组中的每一个值拆分为单独的文档
用法:
{ $unwind: <field path> }
3.2+版本的用法:
增加icludeArrayIndex,preserveNullAndEmptyArrays两个可选配置
{
$unwind:
{
path: <field path>,
includeArrayIndex: <string>,
preserveNullAndEmptyArrays: <boolean>
}
}
字段 类型 描述
path string 必填,数组的字段名,指定需要拆分的字段
includeArrayIndex string 可选,定义返回的字段名,返回的值是拆分前值在原数组的位置
preserveNullAndEmptyArrays boolean 可选,配置在path的值为空或缺失的情况下是否拆分, 默认false
示例:

假设articles文档集合是这样:

{ title: 'this is article A', author: 'John', _id: , comments: ['a', 'b', 'c']}
db.articles.aggregate([{ $unwind: '$comments' }]);

结果:

[
{ title: 'this is article A', author: 'John', _id: , comments: 'a'},
{ title: 'this is article A', author: 'John', _id: , comments: 'b'},
{ title: 'this is article A', author: 'John', _id: , comments: 'c'},
]
进阶示例(v3.2+):

假设articles文档集合是这样:

[
{ title: 'this is article A', author: 'John', _id: , comments: ['a', 'b', 'c'] }
{ title: 'this is article B', author: 'Jack', _id: },
{ title: 'this is article C', author: 'Amy', _id: , comments: [] },
{ title: 'this is article D', author: 'Lam', _id: , comments: null },
]

操作:

db.articles.aggregate([
{
$unwind: {
path: '$comments',
includeArrayIndex: 'arrayIndex',
}
}
]);

结果:

[
{ title: 'this is article A', author: 'John', _id: , comments: 'a', arrayIndex: NumberLong() },
{ title: 'this is article A', author: 'John', _id: , comments: 'b', arrayIndex: NumberLong() },
{ title: 'this is article A', author: 'John', _id: , comments: 'c', arrayIndex: NumberLong() },
]

操作:

db.articles.aggregate([
{
$unwind: {
path: '$comments',
preserveNullAndEmptyArrays: true,
}
}
]);

结果:

[
{ title: 'this is article A', author: 'John', _id: , comments: 'a' },
{ title: 'this is article A', author: 'John', _id: , comments: 'b' },
{ title: 'this is article A', author: 'John', _id: , comments: 'c' },
{ title: 'this is article B', author: 'Jack', _id: },
{ title: 'this is article C', author: 'Amy', _id: },
{ title: 'this is article C', author: 'Amy', _id: , comments: null }
]

$lookup 连接操作符

说明:
用于连接同一个数据库中另一个集合,并获取指定的文档,类似于populate
用法:
{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}
字段 描述
from 需要关联的集合名
localField 本集合中需要查找的字段
foreignField 另外一个集合中需要关联的字段
as 输出的字段名
示例:
  • ariticles中的author关联到user表
  • authoer字段返回详细的用户的信息
db.articles.aggregate([
{
$lookup:
{
from: "users",
localField: "author",
foreignField: "name",
as: "author"
}
}
])

结果:

[
{
title: 'this is article A',
author: {
name: 'John',
age: ,
sex: male,
city: guangzhou,
_id: ,
...
},
_id: ,
...
},
{
title: 'this is article B',
author: {
name: 'Jack',
age: ,
sex: male,
city: guangzhou,
_id: ,
...
},
_id: ,
...
},
{
title: 'this is article C',
author: {
name: 'Rose',
age: ,
sex: male,
city: beijing,
_id: ,
...
},
_id: ,
...
},
{
title: 'this is article D',
author: {
name: 'John',
age: ,
sex: male,
city: guangzhou,
_id: ,
...
},
_id: ,
...
},
{
title: 'this is article E',
author: {
name: 'John',
age: ,
sex: male,
city: guangzhou,
_id: ,
...
},
_id: ,
...
},
...
]

综合示例

需求

找出发表文章最多的5位作者,按发表文章排序,显示他的发表文章的总次数,和他自己的信息

  • 文章按照作者分组,统计次数
  • 按照次数从高到低排序
  • 截取头5名
  • 关联用户信息
  • 不输出文章_id
操作
db.articles.aggregate([
{
$group:
{
_id: "$author",
count: { $sum: },
}
},
{
$sort: { count: - }
},
{
$skip:
},
{
$lookup:
{
from: "users",
localField: "author",
foreignField: "name",
as: "author"
}
},
{
$project: {
_id: ,
}
}
])

总结

本文介绍了几个使用聚合管道查询时常用的管道操作符的用法,熟练地综合使用以上操作符可以对数据进行多样的处理,组合,统计,得出多样化的数据。另外再加以配合表达式操作符(Expression Operators)组成的表达式, 或者在$project或$group中使用累加器(Accumulators)能查询统计的内容会更加的多样化。

【mongoDB查询进阶】聚合管道(二) -- 阶段操作符的更多相关文章

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

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

  2. 【mongoDB查询进阶】聚合管道(一) -- 初识

    https://segmentfault.com/a/1190000010618355 前言:一般查询可以通过find方法,但如果是比较复杂的查询或者数据统计的话,find可能就无能为力了,这时也许你 ...

  3. MongoDB学习day06--高级查询aggregate聚合管道和nodejs操作aggregate

    一.MongoDB聚合管道(Aggregation Pilpeline) 使用聚合管道可以对集合中的文档进行变换和组合. 主要功能:表的关联查询.数据统计 二.aggregate 管道操作符与表达式 ...

  4. MongoDB 高级查询_aggregate聚合管道

    MongoDB 聚合管道(AggregationPipeline) 使用聚合管道可以对集合中的文档进行变换和组合.实际项目应用主要是表关联查询.数据的统计. MongoDB 中使用 db.COLLEC ...

  5. C# MongoDB 查询,分组,聚合,排序,条件,分页

    先下载个C#的驱动.MongoDB提供各种主流与非主流预言的开发驱动. C# Driver 下载地址:这里 CSharp Driver Tutorial:这里 下载文件安装或者解压缩包 如果您是安装, ...

  6. MongoDB小结27 - 聚合管道【$project】

    我们有这样的数据 { "_id" : 1, title: "abcdef", isbn: "6969696969", author: { l ...

  7. Mongodb - 解决 ( aggregate聚合管道 ) $match 根据 id 匹配 返回 [ ] 的问题

    需要对 id 进行转换 const mongoose = require('mongoose') var ObjectId = mongoose.Types.ObjectId;   await Use ...

  8. mongdb的聚合管道

    我们先介绍一下 MongoDB 的聚合功能,聚合操作主要用于对数据的批量处理,往往将记录按条件分组以后,然后再进行一系列操作,例如,求最大值.最小值.平均值,求和等操作.聚合操作还能够对记录进行复杂的 ...

  9. 快速掌握mongoDB(二)——聚合管道和MapReduce

    上一节简单介绍了一下mongoDB的增删改查操作,这一节将介绍其聚合操作.我们在使用mysql.sqlserver时经常会用到一些聚合函数,如sum/avg/max/min/count等,mongoD ...

随机推荐

  1. [译]在Linux上的提高MySQL/MariaDB安全性的12条建议

    MySQL 是世界上最流行的开源数据库系统,而MariaDB(MySQL的一个分支)是世界上发展最快的开源数据库系统.安装MySQL服务器之后,它的默认配置是不安全的,保护它是一般数据库管理中的基本任 ...

  2. pyHook和pythoncom的安装

    pyHook包为Windows中的全局鼠标和键盘事件提供回调.Python应用程序为用户输入事件注册事件处理程序,例如鼠标左键,鼠标左键,按键等,并设置键盘和/或鼠标挂钩.底层C库报告的信息包括事件的 ...

  3. python之restful api(flask)获取数据

    需要用到谷歌浏览器的扩展程序 Advanced Rest Client进行模拟请求 1.直接上代码 from flask import Flask from flask import request ...

  4. 前后端分离djangorestframework——分页组件

    Pagination 为什么要分页也不用多说了,大家都懂,DRF也自带了分页组件 这次用  前后端分离djangorestframework——序列化与反序列化数据  文章里用到的数据,数据库用的my ...

  5. 前后端分离djangorestframework——路由组件

    在文章前后端分离djangorestframework——视图组件 中,见识了DRF的视图组件强大,其实里面那个url也是可以自动生成的,就是这么屌 DefaultRouter urls文件作如下调整 ...

  6. SogouCloud.exe进程导致SQL Server服务无法启动

    早上打开笔记本想开启SQL Server服务时报错,于是根据提示查看windows日志: 依次点开报错发现第一条是1433端口被占用,于是找相关的进程: 于是杀掉此进程: taskkill /pid ...

  7. mcelog用法详解

    手动启动mcelog方法: # mcelog --daemon Run mcelog in daemon mode, waiting for errors from the kernel. 后台服务启 ...

  8. Linux进程调度策略的发展和演变--Linux进程的管理与调度(十六)

    1 前言 1.1 进程调度 内存中保存了对每个进程的唯一描述, 并通过若干结构与其他进程连接起来. 调度器面对的情形就是这样, 其任务是在程序之间共享CPU时间, 创造并行执行的错觉, 该任务分为两个 ...

  9. 阿里云ECS Ubuntu16.0 安装 uwsgi 失败解决方案

    Ubuntu安装包时报错 E:Unable to locate package xxx(如:python3-pip) 一般新安装Ubuntu后需要先更新软件源: apt-get update apt- ...

  10. Ubuntu 12.04上安装 MongoDB并运行

    Ubuntu 12.04上安装 MongoDB并运行 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 在Terminal输入 sudo apt-key ...