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. MySql数据库实现分布式的主从结构

    最近学习了关于使用MySql数据的实现主动结构的原理,在以前的并发访问低的场景一下,一般一台性能高的服务器作为一个MySql数据,就可以满足业务的增删改查场景,但是随着网络用户的增加 当出现高并发,高 ...

  2. Android 程序崩溃之后fragment出现画面重叠问题

    1.解决方法: 直接在包含Fragment的Activity中复写onSaveInstanceState()方法,使其空实现 @Override protected void onSaveInstan ...

  3. Android为TV端助力 android 在5.0以后不允许使用隐式Intent方式来启动Service

    android5.0以后不能使用隐式intent :需要指定Intent的ComponentName信息:intent.setComponent(xxx),或指定Intent的setPackage(& ...

  4. 在线图片上传、预览、裁切、放大、缩小之 cropbox.js 的应用

    cropbox.js 是一个实现了图像在线剪裁的 jQuery .YUI 插件和 JavaScript 库. 上DEMO: 上传的图片可以使用滚轮放大与缩小当前选择的图片,后点击“裁切”后,在右侧的预 ...

  5. Scala隐式参数

    Scala方法可以具有隐式参数列表,由参数列表开头的implicit关键字标记.如果参数列表中的参数没有像往常一样传递,Scala将查看它是否可以获得正确类型的隐式值,如果可以,将自动传递. Scal ...

  6. Microsoft SQL Server 17导出xlsx文件时报错:The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine. (System.Data)

    导出数据时报错: 如果你是导出office 2007格式 TITLE: SQL Server Import and Export Wizard ---------------------------- ...

  7. 批量修改所有服务器的dbmail配置

    最近遇到这样一个案例,需要修改所有SQL Server的Database Mail的SMTP,原来的SMTP为10.xxx.xxx.xxx, 现在需要修改为192.168.xxx.xxx, 另外需要规 ...

  8. 洗礼灵魂,修炼python(65)--爬虫篇—BeautifulSoup:“忘掉正则表达式吧,我拉车养你”

    前面解析了正则表达式,其实内容还挺多的对吧?确实挺适用的,不仅是python,其他语言或者web前端后端基本都要掌握正则表达式知识,但是你说,这么多,要完全的掌握,灵活运用的话,得搞多久啊?并且如果一 ...

  9. asp.net Web项目中使用Log4Net进行错误日志记录

      使用log4net可以很方便地为应用添加日志功能.应用Log4net,开发者可以很精确地控制日志信息的输出,减少了多余信息,提高了日志记录性能.同时,通过外部配置文件,用户可以不用重新编译程序就能 ...

  10. 【2018.05.05 C与C++基础】C++中的自动废料收集:概念与问题引入

    在阅读C++语言的设计与演化一书时,作者多次提到希望能设计出一个自动废料收集,然而出于种种考虑,始终未将自动废料收集纳入标准讨论中,而是由Coder自己考虑是否在程序中实现废料收集. 当然了,许多Ja ...