上一篇文章提到了流水线算子。这篇文章会详细讲管道算子。mongoDB查询进阶--聚合管道(一)回顾什么是管道运算符(AggregationPipelineOperators)mongoDB有4种用于文档操作的运算符,比如find查询中使用的$gte和$in。运算符以$开头,分为四类:查询运算符、更新运算符、管道运算符和查询修饰符。其中管道运算符是聚合管道中使用的运算符。流水线运算符的分类流水线运算符可分为三类:阶段运算符(StageOperators)、表达式运算符(ExpressionOperators)和累加器(Accumulators)。谢谢。参考MongoDB官网:https://docs.mongodb.com/manual/reference/operator/aggregation/#accumulators阶段操作符(StageOperators)阶段操作符用在db.collection.aggregate方法中,第一个在数组参数层。db.collection.aggregate([{stageoperator:expression},{stageoperator:expression},...])表达式运算符表达式运算符主要在管道中构建表达式时使用,使用需要类似函数的参数,主要是在$project运算符中用于构建表达式。使用方法一般如下:方法一:{:[,...]}方法二:{:}累加器(Accumulators)累加器只能是在$groud中使用,但在3.2或以上版本中,一些累加器也可以在$project中使用。在$group中使用时,累加器用于每个组;在$project中使用时,累加器适用于每个文字值。具体用法将在下一篇文章中讲解。由于算子较多,本文先讨论第一类阶段算子,后两类将在下一篇文章中讨论。常用阶段操作符简单说明$match匹配操作符,用于过滤文档集合$project投影操作符,用于重构每个文档的字段,可以提取字段,重命名字段,甚至可以修改原有的字段一个新的字段是在操作之后添加$sort排序运算符,用于按照一个或多个字段对文档进行排序$limit限制运算符,用于限制返回文档的数量$skip跳过运算符,用于跳过指定数量的文档$count统计运算符,使用统计文档的数量$group分组运算符,用于对文档集合进行分组$unwindsplit运算符,用于将数组中的每个值拆分为单独的文档$lookup连接运算符,用于连接到同一数据库中的另一个集合和获取指定文档,类似于populate。更多operator的详细介绍可以参考官网:https://docs.mongodb.com/manual/reference/operator/aggregation/PhaseOperator详解假设有一个User集合,用于存储用户,一个文章的文章集合。数据大致如下:users:[{name:'John',age:16,sex:male,city:guangzhou,_id:1,...},{name:'Rose',age:18,sex:female,city:beijing,_id:2,...},{name:'Jack',age:29,sex:male,city:guangzhou,_id:3,...},{name:'Allen',年龄:18,性别:女,城市:北京,_id:4,...},{name:'Cruz',年龄:22,性别:男,城市:广州,_id:5,...},{name:'Peter',age:18,sex:male,city:guangzhou,_id:6,...},{name:'Kelly',age:23,sex:female,city:shanghai,_id:7,...},...]articles:[{title:'这是艺术icleA',author:'John',_id:1,...},{title:'这是文章B',author:'Jack',_id:2,...},{title:'这是articleC',author:'Rose',_id:3,...},{title:'这是文章D',author:'John',_id:4,...},{title:'thisisarticleE',author:'John',_id:5,...},...]$match匹配运算符说明:用于重构每个文档的字段,可以提取字段,重命名字段,甚至新建对原字段进行操作后的字段用法:{$match:{}}示例:查询年龄为18岁的用户db.users.aggregate([{$match:{age:"18"}}]);$projectProjectionoperatordescription:用于过滤文档集合Usage:{$project:{}}SpecificationrulesRuledescription:1ortrue选择需要返回的Field_id:0orfalse不返回_id(默认返回):expression使用表达式,可以用来重命名一个字段,或者对其值进行操作,或者添加一个新的字段:0orfalse来选择什么不需要返回字段。注意:使用这种用法时,不要使用上面的方法。示例1:从用户集合中投影用户名不返回_iddb.users.aggregate([{$project:{name:1}}]);示例2:将_id重命名为userId不返回_id_db.users.aggregate([{$project:{ueserId:'$_id',_id:0}}]);例3:返回新的字段username,并使用表达式将其值变成name的大写db.users.aggregate([{$project:{name:1,username:{$toUpper:'$name'},_id:0}}]);关于管道表达式:最简单的“$project”表达式是包含和排除字段(例如:{name:1})和字段名称$fieldname(例如:{userId:'$_id'})。此外,还可以使用表达式运算符(如:$toUpper)组成更丰富的表达式,将多个字面量和变量组合起来,得到更有趣的值。更多表达式运算符的使用说明和用法在另外一章详细介绍。$sort排序运算符说明:用于根据一个或多个字段对文档进行排序用法:{$sort:{:,:...}}示例:用户集合按年龄从低到高排序db.users.aggregate([{$sort:{age:1}}]);$limit限制运算符说明:用于限制返回文档的数量用法:{$limit:}示例:return5articlesdb.articles.aggregate({$limit:3});$skip跳过操作符说明:用于跳过指定数量的文档用法:{$skip:<正整数>}示例:跳过1个文档db.users.aggregate([{$skip:1}]);$count统计运算符描述:用于统计文档的数量用法:{$count:}stringisstatistics输出统计结果的字段名示例:统计文章总数,返回totalArticledb.articles.aggregate([{totalArticle:1}]);$group分组操作符说明:用于对文档集合进行分组用法:{$group:{_id:,:{:},...}_id是必填项,使用作为分组的依据。示例:按性别(sex)对用户(users)进行分组db.users.aggregate([{$group:{_id:'$sex'}}]);返回结果:[{_id:'male'},{_id:'female'}]进阶示例:combineUsers(用户)按性别(sex)分组,然后计算每个性别的平均年龄来统计人数不同性别的人,并返回db.users.aggregate([{$group:{_id:'$sex',avgAge:{$avg:'$age'},conut:{$sum:1}}}]);returnresult:[{_id:'男性',avgAge:<男性平均年龄>,count:<男性人数>},{_id:'女性',avgAge:<女性平均年龄>,count:<女性人数>}]这里使用的表达式{$avg:'$age'}用于计算平均年龄,$avg为计算平均值的运算符,$sum用于汇总,这两个累加器只能用于$group,mongoDB3.2及以上版本也可以在$project中使用,具体会在另外一章中详述$unwind拆分操作符说明:用于将数组中的每个值拆分成单独的文档用法:{$unwind:}3.2+版本用法:增加icludeArrayIndex、preserveNullAndEmptyArrays两个可选配置{$unwind:{path:,includeArrayIndex:,preserveNullAndEmptyArrays:}}字段类型说明pathstring必填,数组的字段名,指定要拆分的字段includeArrayIndexstring可选,定义返回的字段名,返回值为拆分前的值在原数组中的位置preserveNullAndEmptyArraysboolean可选,配置path为空或缺失时是否拆分,默认为false示例:假设文章文档集合是这样的:{title:'this是文章A',作者:'John',_id:1,评论:['a','b','c']}db.articles.aggregate([{$unwind:'$comments'}]);结果:[{title:'thisisarticleA',author:'John',_id:1,comments:'a'},{title:'thisisarticleA',author:'John',_id:1,comments:'b'},{title:'thisisarticleA',author:'John',_id:1,comments:'c'},]高级示例(v3.2+):假设集合了articles文档是这样的:[{title:'thisisarticleA',author:'John',_id:1,comments:['a','b','c']}{title:'thisisarticleB',作者:'Jack',_id:2},{title:'这是文章C',author:'Amy',_id:3,comments:[]},{title:'这是文章D',author:'Lam',_id:4,comments:null},]操作:db.articles.aggregate([{$unwind:{path:'$comments',includeArrayIndex:'arrayIndex',}}]);结果:[{title:'thisisarticleA',author:'John',_id:1,comments:'a',arrayIndex:NumberLong(0)},{title:'这是文章A',author:'John',_id:1,comments:'b',arrayIndex:NumberLong(1)},{title:'thisisarticleA',author:'John',_id:1,comments:'c',arrayIndex:NumberLong(2)},]操作:db.articles.aggregate([{$unwind:{path:'$comments',preserveNullAndEmptyArrays:true,}}]);结果:[{title:'thisisarticleA',author:'John',_id:1,comments:'a'},{title:'这是文章A',author:'John',_id:1,comments:'b'},{title:'这是文章A',author:'John',_ID:1,comments:'c'},{title:'这是文章B',author:'Jack',_id:2},{title:'这是文章C',author:'Amy',_id:3},{title:'thisisarticleC',author:'Amy',_id:3,comments:null}]$lookup连接运算符描述:用于连接同一数据库中的另一个集合,获取指定文档,类似populateusage:{$lookup:{from:,localField:,foreignField:,as:<输出数组字段>}}字段描述from需要关联的集合名localField需要在本集合中查找的字段foreignField需要关联另一个集合中的字段作为输出字段名例:articles中的author关联user表author字段返回详细用户信息db.articles.aggregate([{$lookup:{from:"users",localField:"author",foreignField:"name",as:"author"}}])result:[{title:'这是文章A',作者:{姓名:'约翰',年龄:16,性别:男,城市:广州,_id:1,...},_id:1,...},{title:'这是B篇',author:{name:'Jack',age:29,sex:male,city:guangzhou,_id:3,...},_id:2,...},{title:'这是C篇',author:{name:'Rose',age:18,sex:male,city:beijing,_id:2,...},_id:3,...},{title:'这是D篇',author:{name:'John',age:16,sex:male,city:guangzhou,_id:1,...},_id:4,...},{title:'这是文章E',author:{name:'John',age:16,sex:male,city:guangzhou,_id:1,...},_id:5,...},...]综合示例需要找出发表文章最多的5位作者,按发表文章排序,显示发表文章总数,以及本人信息。文章按作者分组,统计按次数从高到低排序。拦截前5条关联用户信息,不输出article_id操作db.articles.aggregate([{$group:{_id:"$author",count:{$sum:1},}},{$sort:{count:-1}},{$skip:5},{$lookup:{来自:"users",localField:"author",foreignField:"name",as:"author"}},{$project:{_id:0,}}])总结本文介绍了聚合管道查询时常用的几种管道算子的用法。熟练地综合使用以上运算符,可以进行各种数据处理、组合、计数,得到多样化的数据另外,添加由表达式运算符(ExpressionOperators)组成的表达式,或者在$project或$group中使用累加器(Accumulators),内容查询统计会发生更多样化的变化。感谢阅读~