该管道中的每二个工作线程,分组总计正是一种聚合操作)

管道概念

POSIX二十三三十二线程的采纳方法中,
有一种很重庆大学的方式—–流水生产线(亦称作“管道”)方式,“数据成分”流串行地被一组线程按梯次执行。它的行使架构可参看下图:

图片 1

以面向对象的思辨去领略,整个工艺流程,能够知晓为一个数额传输的管道;该管道中的每贰个工作线程,能够精通为一个整个工艺流程的2个做事阶段stage,这么些工作线程之间的搭档是一环扣一环的。靠输入口越近的做事线程,是时序较早的行事阶段stage,它的行事战果会潜移默化下一个工作线程阶段(stage)的劳作结出,即下个级次注重于上2个阶段的出口,上1个阶段的出口成为本阶段的输入。那也是pipeline的3个共有特点!

为了回应用户对简易多少访问的必要,MongoDB2.2版本引入新的法力集合框架(Aggregation
Framework) ,它是数码聚合的1个新框架,其定义类似于数据处理的管道。
各样文书档案通过三个由多少个节点组成的管道,种种节点有和好特有的遵循(分组、过滤等),文书档案经过管道处理后,最终输出相应的结果。管道基本的功用有七个:

一是对文书档案进行“过滤”,也正是筛选出符合条件的文书档案;

二是对文书档案进行“变换”,也正是改变文书档案的输出情势。

此外的一些效果还包含依据有些内定的字段分组和排序等。而且在各种阶段还足以应用表明式操作符总括平均值和拼接字符串等连锁操作。管道提供了八个MapReduce
的代表方案,MapReduce使用绝对来说比较复杂,而管道的兼具稳定的接口(操作符表明),使用相比较不难,对于多数的聚合职分管道一般的话是首要选拔办法。

该框架使用注脚性管道符号来援救类似于SQL Group
By操作的功用,而不再必要用户编写自定义的JavaScript例程。

大多数管道操作会在“aggregate”子句后会跟上“$match”打头。它们用在一块,就类似于SQL的from和where子句,或是MongoDB的find函数。“$project”子句看起来也相当接近SQL或MongoDB中的有个别概念(和SQL分歧的是,它身处表明式尾端)。

接下去介绍的操作在MongoDB聚合框架中是惟一的。与多数关周到据库分裂,MongoDB天生就能够在行/文档内部存款和储蓄器储数组。固然该本性对于全有全无的数量访问十二分便利,可是它对于急需结合投影、分组和过滤操作来编排报告的劳作,却展现非凡复杂。“$unwind”子句将数组分解为单个的成分,并与文书档案的其他部分一同重临。

“$group”操作与SQL的Group
By子句用途相同,可是利用起来却更像是LINQ中的分组运算符。与取回一行平面数据差异,“$group”操作的结果集会显示为一个不住的嵌套结构。正因如此,使用“$group”能够重返聚合音信,例如对于每种分组中的实际文档,总括文书档案全体或部分的数码和平均值。

【原著地址】https://docs.mongodb.com/manual/

聚合(重点)
MongoDB的发生背景是在大数目环境,所谓的大数额实际上也便是拓展的信息征集汇总。那么就必须存在有音讯的总括操作,而那样的总结操作就叫做聚合(直白:分组总计就是一种聚合操作)

管道操作符

管道是由2个个效果节点组成的,那么些节点用管道操作符来进展表示。聚合管道以二个聚集中的全数文书档案作为伊始,然后那么些文书档案从3个操作节点
流向下1个节点
,每种操作节点对文档做相应的操作。这几个操作大概会创制新的文书档案只怕过滤掉一部分不符合条件的文档,在管道中得以对文书档案举办双重操作。

先看贰个管道聚合的例证:

图片 2

管道操作符的品种:

Name

Description

$project

Reshapes a document stream. $project can rename, add, or remove fields as well as create computed values and sub-documents.

$match

Filters the document stream, and only allows matching documents to pass into the next pipeline stage.$match uses standard MongoDB queries.

$limit

Restricts the number of documents in an aggregation pipeline.

$skip

Skips over a specified number of documents from the pipeline and returns the rest.

$unwind

Takes an array of documents and returns them as a stream of documents.

$group

Groups documents together for the purpose of calculating aggregate values based on a collection of documents.

$sort

Takes all input documents and returns them in a stream of sorted documents.

$geoNear

Returns an ordered stream of documents based on proximity to a geospatial point.

管道操作符详细使用验证

  1.  $project: 数据投影,首要用以重命名、增删字段

例如:

db.article.aggregate(

{ $project : {

title : 1 ,

author : 1 ,

}}

);

那样的话结果中就只还有_id,tilte和author七个字段了,暗许情状下_id字段是被含有的,若是要想不包括_id话能够如此:

db.article.aggregate(

{ $project : {

_id : 0 ,

title : 1 ,

author : 1

}});

也得以在$project内使用算术类型表达式操作符,例如:

db.article.aggregate(

{ $project : {

title : 1,

doctoredPageViews : { $add:[“$pageViews”, 10] }

}});

由此选择$add给pageViews字段的值加10,然后将结果赋值给一个新的字段:doctoredPageViews

注:必须将$add总结表达式放到中括号里面

除去使用$project还足以重命名字段名和子文书档案的字段名:

db.article.aggregate(

{ $project : {

title : 1 ,

page_views : “$pageViews” ,

bar : “$other.foo”

}});

也得以添加子文书档案:

db.article.aggregate(

{ $project : {

title : 1 ,

stats : {

pv : “$pageViews”,

foo : “$other.foo”,

dpv : { $add:[“$pageViews”, 10] }

}

}});

发生了二个子文书档案stats,里面包蕴pv,foo,dpv四个字段。

2.$match: 滤波操作,筛选符合条件文书档案,作为下一阶段的输入

   $match的语法和查询表明式(db.collection.find())的语法相同

db.articles.aggregate( [

{ $match : { score : { $gt : 70, $lte : 90 } } },

{ $group: { _id: null, count: { $sum: 1 } } }

] );

  
$match用于获取分数大于70低于或等于90记下,然后将符合条件的笔录送到下一阶段$group管道操作符举行拍卖。

注意:1.无法在$match操作符中使用$where表明式操作符。

         
2.$match尽量出现在管道的前边,这样能够提前过滤文书档案,加速聚集速度。

          3.假若$match出现在最前边的话,能够使用索引来加速查询。

3.  $limit:  限制经过管道的文书档案数量

     $limit的参数只可以是一个正整数

db.article.aggregate(

{ $limit : 5 });

那样的话经过$limit管道操作符处理后,管道内就只剩下前八个文书档案了

  1. $skip: 从待操作集合起来的职位跳过文书档案的多寡

    $skip参数也只能为二个正整数

db.article.aggregate(

{ $skip : 5 });

通过$skip管道操作符处理后,前多少个文档被“过滤”掉

5.$unwind:将数组成分拆分为单独字段

比如:article文书档案中有三个名字为tags数组字段:

> db.article.find()
  { “_id” : ObjectId(“528751b0e7f3eea3d1412ce2”),

“author” : “Jone”, “title” : “Abook”,

“tags” : [  “good”,  “fun”,  “good” ] }

使用$unwind操作符后:

>
db.article.aggregate({$project:{author:1,title:1,tags:1}},{$unwind:”$tags”})
{
        “result” : [
                {
                        “_id” : ObjectId(“528751b0e7f3eea3d1412ce2”),
                        “author” : “Jone”,
                        “title” : “A book”,
“tags” : “good”
                },
                {
                        “_id” : ObjectId(“528751b0e7f3eea3d1412ce2”),
                        “author” : “Jone”,
                        “title” : “A book”,
“tags” : “fun”
                },
                {
                        “_id” : ObjectId(“528751b0e7f3eea3d1412ce2”),
                        “author” : “Jone”,
                        “title” : “A book”,
  “tags” : “good”
                }
        ],
        “ok” : 1
}

在意:a.{$unwind:”$tags”})不要忘了$符号

         
b.借使$unwind目标字段不存在的话,那么该文书档案将被忽略过滤掉,例如:

     >
db.article.aggregate({$project:{author:1,title:1,tags:1}},{$unwind:”$tag”})
    { “result” : [ ], “ok” : 1 }
将$tags改为$tag因不存在该字段,该文书档案被忽视,输出的结果为空

        c.假如$unwind指标字段不是二个数组的话,将会发生错误,例如:

  >
db.article.aggregate({$project:{author:1,title:1,tags:1}},{$unwind:”$title”})

    Error: Printing Stack Trace
    at printStackTrace (src/mongo/shell/utils.js:37:15)
    at DBCollection.aggregate (src/mongo/shell/collection.js:897:9)
    at (shell):1:12
    Sat Nov 16 19:16:54.488 JavaScript execution failed: aggregate
failed: {
        “errmsg” : “exception: $unwind:  value at end of field path must
be an array”,
        “code” : 15978,
        “ok” : 0
} at src/mongo/shell/collection.js:L898

      d.如若$unwind目的字段数组为空的话,该文书档案也将会被忽视。

  6.$group 对数码实行分组

   
$group的时候必必要钦命三个_id域,同时也足以涵盖部分算术类型的表达式操作符:

db.article.aggregate(

{ $group : {

_id : “$author”,

docsPerAuthor : { $sum : 1 },

viewsPerAuthor : { $sum : “$pageViews” }

}});

留神:  1.$group的输出是严节的。

         
2.$group操作方今是在内部存款和储蓄器中进行的,所以不可能用它来对多量个数的文书档案实行分组。

7.$sort : 对文书档案遵照钦赐字段排序

行使格局如下:

db.users.aggregate( { $sort : { age : -1, posts: 1 } });

依照年龄进行降序操作,依据posts进行升序操作

在意:1.假如将$sort放到管道前边的话能够选拔索引,升高作用

        2.MongoDB
24.对内部存款和储蓄器做了优化,在管道中若是$sort出现在$limit在此以前的话,$sort只会对前$limit个文书档案进行操作,这样在内部存储器中也只会保留前$limit个文书档案,从而能够大幅的节约内部存款和储蓄器

       
3.$sort操作是在内部存款和储蓄器中展开的,若是其占用的内部存款和储蓄器超越物理内部存款和储蓄器的百分之十,程序会生出错误

8.$goNear

       
$goNear会返回一些坐标值,这几个值以依据距离钦命点离开由近到远举办排序

实际使用参数见下表:

Field

Type

Description

near

GeoJSON point orlegacy coordinate pairs

The point for which to find the closest documents.

distanceField

string

The output field that contains the calculated distance. To specify a field within a subdocument, use dot notation.

limit

number

Optional. The maximum number of documents to return. The default value is 100. See also the num option.

num

number

Optional. The num option provides the same function as the limitoption. Both define the maximum number of documents to return. If both options are included, the num value overrides the limit value.

maxDistance

number

Optional. A distance from the center point. Specify the distance in radians. MongoDB limits the results to those documents that fall within the specified distance from the center point.

query

document

Optional. Limits the results to the documents that match the query. The query syntax is the usual MongoDB read operation query syntax.

spherical

Boolean

Optional. If true, MongoDB references points using a spherical surface. The default value is false.

distanceMultiplier

number

Optional. The factor to multiply all distances returned by the query. For example, use the distanceMultiplier to convert radians, as returned by a spherical query, to kilometers by multiplying by the radius of the Earth.

includeLocs

string

Optional. This specifies the output field that identifies the location used to calculate the distance. This option is useful when a location field contains multiple locations. To specify a field within a subdocument, usedot notation.

uniqueDocs

Boolean

Optional. If this value is true, the query returns a matching document once, even if more than one of the document’s location fields match the query. If this value is false, the query returns a document multiple times if the document has multiple matching location fields. See $uniqueDocsfor more information.

例如:

db.places.aggregate([

{

$geoNear: {

near: [40.724, -73.997],

distanceField: “dist.calculated”,

maxDistance: 0.008,

query: { type: “public” },

includeLocs: “dist.location”,

uniqueDocs: true,

num: 5

}

}

])

其结果为:

{

“result” : [

{ “_id” : 7,

“name” : “Washington Square”,

“type” : “public”,

“location” : [

[ 40.731, -73.999 ],

[ 40.732, -73.998 ],

[ 40.730, -73.995 ],

[ 40.729, -73.996 ]

],

“dist” : {

“calculated” : 0.0050990195135962296,

“location” : [ 40.729, -73.996 ]

}

},

{ “_id” : 8,

“name” : “Sara D. Roosevelt Park”,

“type” : “public”,

“location” : [

[ 40.723, -73.991 ],

[ 40.723, -73.990 ],

[ 40.715, -73.994 ],

[ 40.715, -73.994 ]

],

“dist” : {

“calculated” : 0.006082762530298062,

“location” : [ 40.723, -73.991 ]

}

}

],

“ok” : 1}

个中,dist.calculated中蕴藏了总括的结果,而dist.location中包蕴了总括距离时实际应用的坐标

只顾: 1.应用$goNear只可以在管道处理的起来首先个阶段展开

         2.供给钦定distanceField,该字段用来控制是不是含有距离字段

3.$gonNear和geoNear命令相比一般,可是也有局地例外:distanceField在$geoNear中是必选的,而在geoNear中是可选的;includeLocs在$geoNear中是string类型,而在geoNear中是boolen类型。

聚合

以下的函数 理解即可

管道表达式

管道操作符作为“键”,所对应的“值”叫做管道表达式。例如地点例子中{$match:{status:”A”}},$match称为管道操作符,而{status:”A”}称为管道表明式,它能够当作是管道操作符的操作数(Operand),各类管道表达式是二个文书档案结构,它是由字段名、字段值、和有个别表达式操作符组成的,例如地点例子中管道表明式就含有了八个表明式操作符$sum实行累加求和。

各类管道表达式只可以作用于处理当下正值处理的文书档案,而无法开始展览跨文档的操作。管道表明式对文书档案的拍卖都以在内部存款和储蓄器中开始展览的。除了能够举办添加总括的管道表达式外,其他的表明式都是无状态的,也正是不会保留上下文的音信。累加性质的表明式操作符平日和$group操作符一起利用,来总括该组内最大值、最小值等,例如地点的例证中大家在$group管道操作符中使用了拥有充裕的$sum来计量总和。

而外$sum以为,还有以下性质的表达式操作符:

组聚集操作符

Name

Description

$addToSet

Returns an array of all the unique values for the selected field among for each document in that group.

$first

Returns the first value in a group.

$last

Returns the last value in a group.

$max

Returns the highest value in a group.

$min

Returns the lowest value in a group.

$avg

Returns an average of all the values in a group.

$push

Returns an array of all values for the selected field among for each document in that group.

$sum

Returns the sum of all the values in a group.

Bool类型聚合操作符

Name

Description

$and

Returns true only when all values in its input array are true.

$or

Returns true when any value in its input array are true.

$not

Returns the boolean value that is the opposite of the input value.

比较类型聚合操作符

Name

Description

$cmp

Compares two values and returns the result of the comparison as an integer.

$eq

Takes two values and returns true if the values are equivalent.

$gt

Takes two values and returns true if the first is larger than the second.

$gte

Takes two values and returns true if the first is larger than or equal to the second.

$lt

Takes two values and returns true if the second value is larger than the first.

$lte

Takes two values and returns true if the second value is larger than or equal to the first.

$ne

Takes two values and returns true if the values are not equivalent.

算术类型聚合操作符

Name

Description

$add

Computes the sum of an array of numbers.

$divide

Takes two numbers and divides the first number by the second.

$mod

Takes two numbers and calcualtes the modulo of the first number divided by the second.

$multiply

Computes the product of an array of numbers.

$subtract

Takes two numbers and subtracts the second number from the first.

字符串类型聚合操作符

Name

Description

$concat

Concatenates two strings.

$strcasecmp

Compares two strings and returns an integer that reflects the comparison.

$substr

Takes a string and returns portion of that string.

$toLower

Converts a string to lowercase.

$toUpper

Converts a string to uppercase.

日子类型聚合操作符

Name

Description

$dayOfYear

Converts a date to a number between 1 and 366.

$dayOfMonth

Converts a date to a number between 1 and 31.

$dayOfWeek

Converts a date to a number between 1 and 7.

$year

Converts a date to the full year.

$month

Converts a date into a number between 1 and 12.

$week

Converts a date into a number between 0 and 53

$hour

Converts a date into a number between 0 and 23.

$minute

Converts a date into a number between 0 and 59.

$second

Converts a date into a number between 0 and 59. May be 60 to account for leap seconds.

$millisecond

Returns the millisecond portion of a date as an integer between 0 and 999.

条件类型聚合操作符

Name

Description

$cond

A ternary operator that evaluates one expression, and depending on the result returns the value of one following expressions.

$ifNull

Evaluates an expression and returns a value.

注:以上操作符都不可能不在管道操作符的表明式内来使用。

逐条表明式操作符的具体使用办法参见:

http://docs.mongodb.org/manual/reference/operator/aggregation-group/

聚拢操作处理数量记录并再次来到总结后的结果。聚合操作将多少个文书档案分组,并能对已分组的数量实施一层层操作而回到单一结果。MongoDB提供了三种实施聚合的艺术:聚合管道,map-reduce方法和单一目标聚合操作。

1.到手集合的数据量

对于集合的数据量而言,在MongoDB里面向来利用count()函数就足以形成了。

集聚管道的优化

   1.$sort  +  $skip  +  $limit顺序优化

如果在履行政管理道聚合时,假设$sort、$skip、$limit依次出现以来,例如:

{ $sort: { age : -1 } },

{ $skip: 10 },

{ $limit: 5 }

那正是说实际上施行的相继为:

{ $sort: { age : -1 } },

{ $limit: 15 },

{ $skip: 10 }

$limit会提前到$skip前边去实施。

此时$limit = 优化前$skip+优化前$limit

那般做的便宜有几个:1.在通过$limit管道后,管道内的文书档案数量个数会“提前”减小,那样会节省外部存款和储蓄器,进步内部存储器利用功用。2.$limit提内外,$sort紧邻$limit那样的话,当进行$sort的时候当获得前“$limit”个文书档案的时候就会停下。

2.$limit + $skip + $limit + $skip Sequence Optimization

假诺聚合管道内反复出现上边包车型大巴联谊系列:

  { $limit: 100 },

  { $skip: 5 },

  { $limit: 10},

  { $skip: 2 }

首先实香港行政局地优化为:能够服从地点所讲的先将第一个$limit提前:

{ $limit: 100 },

  { $limit: 15},

  { $skip: 5 },

  { $skip: 2 }

更为优化:八个$limit能够一贯取最小值 ,多个$skip能够平素相加:

{ $limit: 15 },

  { $skip: 7 }

3.Projection Optimization

过早的施用$project投影,设置需求利用的字段,去掉不用的字段,能够大大收缩内部存款和储蓄器。除此而外也足以过早使用

大家也应当过早使用$match、$limit、$skip操作符,他们得以提前减弱管道内文书档案数量,收缩内存占用,提供聚合效能。

除外,$match尽量放到聚合的首先个等级,假若这样的话$match相当于一个按规则查询的言辞,那样的话可以利用索引,加速查询效能。

聚集管道

范例:总计students表中的数据量

db.students.count();

聚拢管道的限制

    1.类型限制

在管道内不可能操作 Symbol, MinKey, 马克斯Key, DBRef, Code,
CodeWScope类型的数据( 2.4本子解除了对二进制数据的限量).

     2.结实大小限制

管道线的出口结果不能够跨越BSON 文书档案的轻重(16M),假诺过量的话会发出错误.

     3.内部存款和储蓄器限制

若是二个管道操作符在推行的经过中所占有的内部存款和储蓄器超越系统内部存储器容积的十分之一的时候,会生出八个荒唐。

当$sort和$group操作符执行的时候,整个输入都会被加载到内部存款和储蓄器中,尽管这么些占有内部存款和储蓄器超越系统内存的%5的时候,会将多个warning记录到日志文件。同样,所占据的内部存款和储蓄器当先系统内部存储器体量的一成的时候,会发出一个张冠李戴。

MongoDB的汇集框架模型建立在数额处理管道这一概念的底蕴之上。文书档案进入多阶段管道中,管道将文书档案转换为汇集结果。最核心的管道阶段类似于查询过滤器和修改出口文书档案情势的文书档案转换器。

范例:带有模糊查询的总结

db.students.count({"name":/张/i});

在开始展览新闻查询的时候,不设置标准永远要比设置规范的查询快很多,也正是说在前头的代码编写内部不管是询问任何要么模糊查询,实际上最后都使用的混淆查询一种(没有设置重庆大学字)。

分片上利用聚合管道

集结管道协理在已分片的汇聚上拓展联谊操作。当分片集合上举行联谊操纵的时候,聚合管道被分成两成七个部分,分别在mongod实例和mongos上开始展览操作。

其余的管道为分组和排序提供部分工具,可透过点名1个或四个字段完毕分组或排序;同时提供了聚合数组内容的工具,操作的数组包含文书档案数组。其它,聚合阶段能够利用一些运算符,完结诸如总结均值或一而再字符串之类的职责。

2.免去重复数据

在读书SQL的时候对于再度的数额可以使用“DISTINCT”,那么这一操作在MongoDB之中依旧帮助。

汇集管道使用

率先下载测试数据:http://media.mongodb.org/zips.json 并导入到数据库中。

1.查询外地的人口数

var connectionString =
ConfigurationManager.AppSettings[“MongodbConnection”];

var client = new MongoClient(connectionString);

var DatabaseName = ConfigurationManager.AppSettings[“DatabaseName”];

string collName = ConfigurationManager.AppSettings[“collName”];

MongoServer mongoDBConn = client.GetServer();

MongoDatabase db = mongoDBConn.GetDatabase(DatabaseName);

MongoCollection<BsonDocument> table = db[collName];

var group = new BsonDocument

{

{“$group”, new BsonDocument

{

{

“_id”,”$state”

},

{

“totalPop”, new BsonDocument

{

{ “$sum”,”$pop” }

}

}

}

}

};

var sort = new BsonDocument

{

{“$sort”, new BsonDocument{ { “_id”,1 }}}

};

var pipeline = new[] { group, sort };

var result = table.Aggregate(pipeline);

var matchingExamples = result.ResultDocuments.Select(x =>
x.ToDynamic()).ToList();

foreach (var example in matchingExamples)

{

var message = string.Format(“{0}- {1}”, example[“_id”],
example[“totalPop”]);

Console.WriteLine(message);

}

2.总结各类州平均每一个城市打人口数

>
db.zipcode.aggregate({$group:{_id:{state:”$state”,city:”$city”},pop:{$sum:”$pop”}}},

                             
{$group:{_id:”$_id.state”,avCityPop:{$avg:”$pop”}}},

                                       {$sort:{_id:1}})

var group1 = new BsonDocument

{

{“$group”, new BsonDocument

{

{

“_id”,new BsonDocument

{

{“state”,”$state”},

{“city”,”$city”}

}

},

{

“pop”, new BsonDocument

{

{ “$sum”,”$pop” }

}

}

}

}

};

var group2 = new BsonDocument

{

{“$group”, new BsonDocument

{

{

“_id”,”$_id.state”

},

{

“avCityPop”, new BsonDocument

{

{ “$avg”,”$pop” }

}

}

}

}

};

var pipeline1 = new[] { group1,group2, sort };

var result1 = table.Aggregate(pipeline1);

var matchingExamples1 = result1.ResultDocuments.Select(x =>
x.ToDynamic()).ToList();

foreach (var example in matchingExamples1)

{

var message = string.Format(“{0}- {1}”, example[“_id”],
example[“avCityPop”]);

Console.WriteLine(message);

}

3.计量每一个州人口最多和最少的都市名字

>db.zipcode.aggregate({$group:{_id:{state:”$state”,city:”$city”},pop:{$sum:”$pop”}}},

                                      {$sort:{pop:1}},

                                     
{$group:{_id:”$_id.state”,biggestCity:{$last:”$_id.city”},biggestPop:{$last:”$pop”},smallestCity:{$first:”$_id.city”},smallestPop:{$first:”$pop”}}},

                                     
{$project:{_id:0,state:”$_id”,biggestCity:{name:”$biggestCity”,pop:”$biggestPop”},smallestCity:{name:”$smallestCity”,pop:”$smallestPop”}}})

var sort1 = new BsonDocument

{

{“$sort”, new BsonDocument{ { “pop”,1 }}}

};

var group3 = new BsonDocument

{

{

“$group”, new BsonDocument

{

{

“_id”,”$_id.state”

},

{

“biggestCity”,new BsonDocument

{

{“$last”,”$_id.city”}

}

},

{

“biggestPop”,new BsonDocument

{

{“$last”,”$pop”}

}

},

{

“smallestCity”,new BsonDocument

{

{“$first”,”$_id.city”}

}

},

{

“smallestPop”,new BsonDocument

{

{“$first”,”$pop”}

}

}

}

}

};

var project = new BsonDocument

{

{

“$project”, new BsonDocument

{

{“_id”,0},

{“state”,”$_id”},

{“biggestCity”,new BsonDocument

{

{“name”,”$biggestCity”},

{“pop”,”$biggestPop”}

}},

{“smallestCity”,new BsonDocument

{

{“name”,”$smallestCity”},

{“pop”,”$smallestPop”}

}

}

}

}

};

var pipeline2 = new[] { group1,sort1 ,group3, project };

var result2 = table.Aggregate(pipeline2);

var matchingExamples2 = result2.ResultDocuments.Select(x =>
x.ToDynamic()).ToList();

foreach (var example in matchingExamples2)

{

Console.WriteLine(example.ToString());

//var message = string.Format(“{0}- {1}”, example[“_id”],
example[“avCityPop”]);

//Console.WriteLine(message);

}

管道利用MongoDB本机的操作方法提供了实惠的数据聚合操作,并且对于数据聚合来说采用本机的操作方法是首要选取的。

范例:查询全数name的信息

本次的操作没有直接的函数援救,只可以够使用runCommand()函数

db.runCommand({"distinct":"students","key":"name"})

那会儿促成了对于name数据的重复值的筛选。

db.runCommand({"distinct":"tbl_jh_grid_100m","key":"msid"});

总结

对此绝当先5/10的成团操作,聚合管道能够提供很好的性质和同样的接口,使用起来相比较简单,
和MapReduce一样,它也能够功效于分片集合,可是出口的结果只好保留在3个文书档案中,要依照BSON
Document大小限制(当前是16M)。

管道对数据的花色和结果的深浅会有一些范围,对于部分粗略的原则性的成团操作能够运用管道,不过对于有些繁杂的、大批量数据集的集合职分仍然利用MapReduce。

连锁小说:

http://mikaelkoskinen.net/mongodb-aggregation-framework-examples-in-c/

会晤管道帮助在分片集合上执行操作。

3.group操作(分组操作的最终结出是少数的)——不提议选取

应用“group”操作能够兑现数量的分组操作,在MongoDB里面会将聚合一句钦赐的key的两样进行分组操作,并且每1个组都会发出3个处理的文档结果。
以上的操作代码里面实现的就属于一种MapReduce,不过如此只是基于守旧的数据库的铺排性思路,已毕了贰个所谓的分组操作,不过这么些分组操作的最终结果是少数的。

聚拢管道在它的少数阶段能够使用索引来进步品质。其它,聚合管道有七个里面优化阶段。

4.MapReduce操作

MapReduce是全部大数目标精髓所在(实际中别用),所谓的MapReduce便是分为两步处理数量:
· Map:将数据分别取出;
· Reduce:负责数据的尾声的拍卖。
唯独要想在MongoDB里面完毕MapReduce处理,那么复杂度是一对一高的。

 图片 3

会面框架(主题)

MapReduce功效强大,但是它的复杂度和功能雷同强大,那么很多时候我们要求MapReduce的功力,可是又不想把代码写的太复杂,所以从Mongo
2.x版本之后开首引入了聚众框架并且提供了聚合函数:aggregate()。

Map-Reduce

1 $group group首要开始展览分组的数据操作。(基于内部存款和储蓄器总结:不协理大数据量)

MongoDB也能够提供map-reduce操作来达成聚合。一般地,map-reduce操作有七个级次:map 阶段处理每1个文书档案并将每二个输入文书档案映射成一个或五个目的,reduce合成map等级的出口。可选的,map-reduce操作能够有三个finalize等级以对输出做最后的改动。像任何的集结操作一样,

范例:达成聚合查询的功用——求出每种地方的雇员人数
db.emps.aggregate([{"$group":{"_id":"$job",job_count:{"$sum":1}}}])
db.col.aggregate([{"$group":{"_id":"$title",title_count:{"$sum":1}}}])
db.col.aggregate([{"$group":{"_id":"$title",title_count:{"$avg":1}}}])

 map-reduce操作能够钦定询问条件筛选输入文书档案和对结果进行排序和限制。

范例:求出每一种地方的总薪俸
db.emps.aggregate([{"$group":{"_id":"$job",job_sal:{"$sum":"$salary"}}}])

在整整聚合框架之中如若要引用每行的数量运用:“$字段名称”。

db.col.aggregate([{"$group":{"_id":"$title",title_count:{"$sum":"$likes"}}}]);

map-reduce使用自定义JavaScript方法来达成map,reduce和finalize 操作。就算与聚集管道比较,自定义JavaScript提供了高大的油滑,

范例:计算出每一个岗位的平均薪给
db.emps.aggregate([{"$group":{
"_id":"$job",
job_sal:{"$sum":"$salary"},
job_avg:{"$avg":"$salary"}
}}]);

但map-reduce比聚合管道效能低且比聚合管道更复杂。

范例:求出最高与最低薪金
db.emps.aggregate([{"$group":{
"_id":"$job",
job_sal:{"$sum":"$salary"},
job_avg:{"$avg":"$salary"}
}}]);

map-reduce能够在分片集合上实施操作。map-reduce操作也能将数据输出到分片集合上。

测算出种种地方的工薪数据(数组展现)
db.emps.aggregate([{"$group":{
"_id":"$job",
"sal_info":{"$push":"$name"}
}}]);

db.emps.aggregate([{"$group":{
"_id":"$job",
"sal_info":{"$push":"$salary"}
}}]);

利用“$push”的确能够将数据变成数组进行封存,不过有一个题目出现了,重复的始末也会进行保存,那么在MongoDB里面提供有撤除重复的安装。

注:

范例:撤消重复的数码
db.emps.aggregate([{"$group":{
"_id":"$job",
"sal_info":{"$addToSet":"$name"}
}}]);

默许景况下是将有着的多寡都保存进去了,但是以往只希望能够保存第二个大概是终极一个。

从2.4版本起首,有些mongo shell 方法和特点不支持map-reduce操作。2.4本子也扶助同时运营五个JavaScript操作。2.4在此以前的本子,

范例:保存第2个内容
db.emps.aggregate([{"$group":{
"_id":"$job",
"sal_info":{"$first":"$name"}
}}]);

JavaScript代码在单线程中执行,对map-reduce操作来说存在并发难题。

范例:保存最后八个剧情
db.emps.aggregate([{"$group":{
"_id":"$job",
"sal_info":{"$last":"$name"}
}}]);

虽说可以便宜的贯彻分组处理,可是有少数内需专注,全部的分组数据是冬季的,并且都以在内部存款和储蓄器之中实现的,所以不也许支持大数据量。

 图片 4

2 $project

能够运用“$project”来控制数据列的显得规则,那么能够推行的条条框框如下:
|- 普通列({成员 : 1 | true}):表示要展现的内容;
|- “_id”列({“_id” : 0 | false}):表示“_id”列是还是不是出示;
|- 条件过滤列({成员 : 表明式}):知足表明式之后的多寡能够拓展体现。

单纯指标聚合操作

范例:只显示name、job列,不显示“_id”列
db.emps.aggregate([{"$project":{
"_id":0,
"name":1
}}])

这时候唯有设置进去的列才能够被突显出来,而其他的列不可见被出示出来。实际上那就属于数据库的阴影机制。
实在在开始展览数据投影的经过之中也支撑四则运算:加法(“$add”)、减法(“$subtract”)、乘法(“$multiply”)、除法(“$divide”)、求模($mod)。

MongoDB还提供了db.collection.count(),
db.collection.group(), db.collection.distinct()专用数据库命令。

范例:观看四则运算
db.emps.aggregate([{"$project":{
"_id":0,
"name":1,
"职位":"$job",   //相当于重命名job为“职位”
"salary":1
}}]);

db.emps.aggregate([{"$project":{
"_id":0,
"name":1,
"job":1, 
"salary":1
}}]);

db.emps.aggregate([{"$project":{
"_id":0,
"name":1,
"job":1,
"salary":{"年薪":{"$multiply":["$salary",12]}}
}}]);

db.col.aggregate({"$project":{
    "_id":1,
    "likes":{"年薪":{"$multiply":["$likes",12]}}
    }})

除了四则运算之外也支撑如下的各个运算符:
·关系运算:大小相比较(“$cmp”)、等于(“$eq”)、大于(“$gt”)、大于等于(“$gte”)、小于(“$lt”)、小于等于(“$lte”)、不对等(“$ne”)、判断NULL(“$ifNull”),那几个重返的结果都以布尔型数据;
·逻辑运算:与(“$and”)、或(“$or”)、非(“$not”);
·字符串操作:连接(“$concat”)、截取(“$substr”)、转小写(“$toLower”)、转大写(“toUpper”)、不区分轻重缓急写相比较(“$strcasecmp”)。

享有那一个操作从叁个集结中会晤文书档案。尽管这个操作提供了简要的贯彻聚合操作的主意,但是它们不够灵活性和同聚合管道与

范例:找出富有报酬高于等于2000的雇员姓名、年龄、薪俸
db.emps.aggregate([{"$project":{
"_id":0,
"name":1,
"job":1,
"工资":"$salary",
"salary":{"$gte":["$salary",2000]}
}}])

db.col.aggregate({"$project":{
    "_id":1,
    "年薪":{"$multiply":["$likes",12]}
}})

/* 1 */
{
“_id” : ObjectId(“5a338f0181bee14fe8a112e0”),
“年薪” : 2400.0
}

/* 2 */
{
“_id” : ObjectId(“5a338f0981bee14fe8a112e1”),
“年薪” : 1800.0
}

/* 3 */
{
“_id” : ObjectId(“5a338f1281bee14fe8a112e2”),
“年薪” : 1200.0
}

map-reduce相似的性质。

范例:查询职位是manager的新闻

·MongoDB中的数据是分别轻重缓急写的;

db.emps.aggregate([{"$project":{
"_id":0,
"name":1,
"职位":"$job",
"job":{"$eq":["$job","MANAGER"]}
}}]);

db.emps.aggregate([{"$project":{
"_id":0,
"name":1,
"职位":"$job",
"job":{"$eq":["$job",{"$toUpper":"manager"}]}
}}]);


db.emps.aggregate([{"$project":{
"_id":0,
"name":1,
"职位":"$job",
"job":{"$strcasecmp":["$job","manager"]}
}}]);

 图片 5

范例:使用字符串截取

动用“$project”达成的阴影操作作用十分强劲,全体能够出现的操作大约都能够使用。

db.emps.aggregate([{"$project":{
"_id":0,
"name":1,
"职位":"$job",
"job":{"前面三位":{"$substr":["$job",0,3]}}
}}]);

选取“$project”达成的黑影操作成效相当强大,全体能够出现的操作大致都能够利用。

1 聚合管道

3 $match

“$match”是3个滤波操作,正是进展WHERE的过滤。

集结管道是一个白手起家在数据处理管道模型概念基础上的框架。文书档案进入多阶段管道中,管道将文书档案转换为汇聚结果。

范例:查询薪俸在三千 ~5000的雇员

db.emps.aggregate([{"$match":{
"salary":{"$gte":2000,"$lte":5000}
}}]);

那么些时候实现的代码严厉来讲只是相当于“SELECT * FROM 表 WHERE
条件”,属于持有的剧情都开始展览了查询。

db.col.aggregate([{"$match":{
"likes":{"$gte":120}
}}]);

/* 1 */
{
“_id” : ObjectId(“5a338f0181bee14fe8a112e0”),
“title” : “PHP 教程”,
“description” : “PHP
是一种创设动态交互性站点的强有力的劳动器端脚本语言。”,
“by” : “菜鸟教程”,
“url” :
http://www.runoob.com“,
“tags” : [
“php”
],
“likes” : 200.0
}

/* 2 */
{
“_id” : ObjectId(“5a338f0981bee14fe8a112e1”),
“title” : “Java 教程”,
“description” : “Java 是由Sun
七彩虹公司于一九九二年12月出产的高等程序设计语言。”,
“by” : “菜鸟教程”,
“url” :
http://www.runoob.com“,
“tags” : [
“java”
],
“likes” : 150.0
}

 图片 6

范例:控制影子操作

db.emps.aggregate([
{"$match":{"salary":{"$gte":2000,"lte":5000}}},
{"$project":{"_id":0,name:1,salary:1}}
]);

那时候一定于贯彻了“SELECT字段 FROM … WHERE”语句结构。

集结管道提供了map-reduce 的替代品,并且对于 map-reduce的复杂是剩下的聚合职分以来,聚合管道恐怕是首要选拔的缓解方案。

范例:继续分组

db.emps.aggregate([
{"$match":{"salary":{"$gte":2000,"lte":5000}}},
{"$project":{"_id":0,name:1,salary:1,"job":1}},
{"$group":{"_id":"$job","count":{"$num":1},"avg":{"$avg":"$salary"}}}
]);

因此一各类的示范能够计算一点:
·“$project”:相当于SELECT子句;
·“$match :相当于WHERE子句;
·“$group”:相当于GROUP BY子句。

聚拢管道对值的品种和再次来到结果的大大小小做了限定。

4 $sort

利用“$sort”能够完毕排序,设置1意味着升序,设置-1意味降序。

1.1 管道

范例:达成排序

db.emps.aggregate([{"$sort":{"age":-1,"salary":1}}]);

MongoDB 聚合管道由三个级次组成。当文书档案经过逐一管道时,每种管道对文书档案举办更换。对于每贰个输入文书档案,管道各等级不要求发出输出文档。例如,某个阶段只怕会生成新文书档案或过滤掉一部分文书档案。聚合管道的一对等级能够在管道中冒出反复。

范例:将有所的操作一起利用

db.emps.aggregate([
{"$match":{"salary":{"$gte":2000,"lte":5000}}},
{"$project":{"_id":0,name:1,salary:1,"job":1}},
{"$group":{"_id":"$job","count":{"$num":1},"avg":{"$avg":"$salary"}}},
{"$sort":{"count":-1}}
]);

那时贯彻了降序排序,使用的是转变定义的小名。

MongoDB提供了可在mongo shell中施行的db.collection.aggregate()方法和聚众管道命令aggregate。

5 分页处理:$limit、$skip

“$limit”:负责数据的取出个数;
“$skip”:数据的跨过个(行)数。

范例:
db.emps.aggregate([
{“$match”:{“salary”:{“$gte”:2000,”lte”:5000}}},
{“$project”:{“_id”:0,name:1,salary:1,”job”:1}},
{“$group”:{“_id”:”$job”,”count”:{“$num”:1},”avg”:{“$avg”:”$salary”}}},
{“$sort”:{“count”:-1}},
{“$sort”:1},
{“$skip”:1}
]);

db.tbl_jh_grid_100m.aggregate([
{"$project":{"_id":0,"msid":1,"dir":1}},
{"$limit":3}
]);

/* 1 */
{
“msid” : “46B03B557EFF98CC82B32D62E65C35DC”,
“dir” : 0
}

/* 2 */
{
“msid” : “53F8FACD639D9AFD1F0C4DA8E5E0274B”,
“dir” : 0
}

/* 3 */
{
“msid” : “DE1EFABF66DB0FA49D2BF56C8E801EB5”,
“dir” : 0
}

只可以够说以往的查询能够在实质上的开发之中使用了。

1.2 聚合管道表明式

6 $unwind

在查询数据的时候时不时会回来数组音讯,不过数组并不便宜消息的浏览,所以提供有“$unwind”能够将数组数据变成单独的字符串内容。

bus:数组

db.emps.aggregate([
{"$project":{"_id":0,"title":1,"bus":1}},
{"$unwind":"$bus"}
]);

这时候一定于将数组中的数据变成了单行的多寡。

某个管道阶段选拔聚合管道表明式作为它的操作数。聚合管道表明式钦赐了采纳于输入文书档案的更换。聚合管道表明式接纳文书档案结构并且能够包含别的聚合管道表明式。

7 $geoNear(不常用)

选取“$geoNear”可以取得附近的坐标点。

{"$geoNear":{"near":[11,12],"distanceField":"loc","maxDistance":1,"num":2,"spherical":true}}
]);

地理音信的搜索必须存在有索引的支撑。

集结管道表明式能够仅作用于管道中的当前文书档案并且不会提到任何文书档案数据:聚合管道表明式协理在内部存款和储蓄器中履行文书档案转换。

8 $out

“$out”:利用此操作能够将查询结果输出到内定的集聚里面。

诚如地,聚合管道表明式是无状态的同时仅在被集结处理进度发现时才被求值,但累加器表明式除了那一个之外。

范例:将影子的结果输出到聚集里

db.emps.aggregate([
{"$project":{"_id":0,"name":1,"salary":1,"job":1}},
{"$out":"emps_infos"}
]);

https://docs.mongodb.com/manual/reference/operator/aggregation
MongoDB 聚合
MongoDB中相会(aggregate)首要用于拍卖数量(诸如总计平均值,求和等),并赶回总括后的数据结果。有点类似sql语句中的
count(*)。

aggregate() 方法
MongoDB中晤面的艺术运用aggregate()。

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

db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

案例:
db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial :
{$sum : 1}}}])
如上实例类似sql语句: select by_user as _id, count(*) as
num_tutorial from mycol group by by_user
在上边的事例中,大家通过字段by_user字段对数码开始展览分组,并盘算by_user字段相同值的总和。
下表显示了有个别凑合的表明式:
表达式 描述 实例
$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文书档案在2个管道处理完成后将结果传递给下二个管道处理。管道操作是足以重新的。

表明式:处理输入文书档案并出口。表达式是无状态的,只好用于总结当前聚集管道的文书档案,不可能处理任何的文书档案。

此间大家介绍一下汇聚框架中常用的多少个操作:

$project:修改输入文书档案的协会。能够用来重命名、扩展或删除域,也得以用来创造计算结果以及嵌套文书档案。
$match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的正儿八经查询操作。
$limit:用来限制MongoDB聚合管道重返的文书档案数。
$skip:在集结管道中跳过内定数量的文书档案,并回到余下的文书档案。
$unwind:将文书档案中的某一个数组类型字段拆分成多条,每条包涵数组中的3个值。
$group:将聚合中的文书档案分组,可用于计算结果。
$sort:将输入文书档案排序后输出。
$geoNear:输出接近某一地理地点的不变文书档案。

管道操作符实例
1、$project实例

db.article.aggregate(
{ $project : {
title : 1 ,
author : 1 ,
}}
);
那样的话结果中就只还有_id,tilte和author多个字段了,私下认可景况下_id字段是被含有的,假使要想不含有_id话能够这么:
db.article.aggregate(
{ $project : {
_id : 0 ,
title : 1 ,
author : 1
}});

2.$match实例

db.articles.aggregate( [
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
] );
$match用于获取分数大于70稍差于或等于90笔录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。

3.$skip实例

db.article.aggregate(
{ $skip : 5 });
由此$skip管道操作符处理后,前多个文书档案被”过滤”掉。

4.按日、按月、按年、按周、按小时、按分钟集合操作如下:
db.getCollection(‘m_msg_tb’).aggregate(
[
{$match:{m_id:10001,mark_time:{$gt:new Date(2017,8,0)}}},
{$group: {
_id: {$dayOfMonth:’$mark_time’},
pv: {$sum: 1}
}
},
{$sort: {“_id”: 1}}
])
岁月重点字如下:

$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: } }。

累加器用在$group阶段,当文书档案经过这些管道时,它们的意况被保存下来(例如总数,最大值,最小值,相关数据)。

3.2本子中的变化:有些累加器在$project阶段可以运用。不过,在$project阶段选用那些累加器时,那几个累加器不会保留它们的情状到文书档案中。

1.3 集合管道行为

在MongoDB中集合命令成效于二个汇集,在逻辑上校整个集合传入聚合管道。为了优化操作,尽恐怕地行使上边包车型大巴策略以制止扫描整个集合。

管道操作符合索引

$match 和$sort管道操作符能够接纳索引,当它们在管道起头处冒出时。

2.4版本的扭转:$geoNear管道操作符能够接纳地理空间引得。当使用$geoNear时,$geoNear管道操作符必须现身在聚集管道的首先等级。

3.2本子中的变化:从3.2本子开首索引能够覆盖三个汇集管道。在2.6
和3.0本子中,索引不可能遮住聚合管道,因为固然管道使用了目录,聚合照旧需求选拔实际的文书档案。

较早地过滤

假使您的联谊操作仅必要集聚中的叁个数量子集,那么使用$match, $limit,和$skip阶段来界定最起先进入管道的文书档案。当被停放管道的上马处时,$match操作使用卓殊的目录,只扫描集合中分外到的文书档案。

在管道的发端处选择后边紧跟了$sort阶段的$match管道阶段,那在逻辑上等价于使用了目录的蕴藏排序的查询操作。尽或许地将$match阶段放在管道的最开首处。

别的的性状

聚拢管道有3个内部最优化阶段,那些等级创新了几许操作的习性。

汇集管道援救分片集合上的操作。

1.4 聚合管道优化

聚拢管道操作有一个优化阶段,此阶段试图重塑管道以改正质量。

为翻动优化程序怎么着立异2个特定的汇集管道,在db.collection.aggregate()方法中使用explain 选项。

1.4.1 投影器优化

会面管道能够判明是或不是选择集合中字段的叁个子集来取得结果。如若选取子集,那么聚集管道将只会使用那个急需的字段以缩减管道中传输的数据量。

1.4.2 管道顺序优化

$sort + $match管道顺序优化

当管道顺序为$sort 后跟$match时, $match会移动到$sort此前以减掉排序对象的数额。例如,即使管道包罗上边包车型地铁级差:

{ $sort: { age : -1 } },{ $match: { status: ‘A’ } }

在优化阶段,优化器将队列顺序改变为上边那样:

{ $match: { status: ‘A’ } },{ $sort: { age : -1 } }

$skip + $limit管道顺序优化

当管道顺序为$skip 后跟$limit时, $limit会移动到$skip 以前以缩减排序对象的数据。顺序改变后,$limit值增添的值为$skip的值。

比如说,假如管道包蕴上边包车型地铁阶段:

{ $skip: 10 },{ $limit: 5 }

在优化阶段,优化器将队列顺序改变为上边那样:

{ $limit: 15 },{ $skip: 10 }

那种优化为$sort +
$limit合并提供越多的空子,例如类别$sort + $skip + $limit。

对此分片集合上的成团操作,那种优化收缩了每3个分片再次回到的结果。

$redact + $match管道顺序优化

当管道包括了后来紧跟$match阶段的$redact阶段时,尽或然地,管道会不时地在 $redact阶段前添加一部分$match阶段。要是加上的$match阶段是管道的初始,管道会在查询的同时采取索引来限制进入管道的文书档案数量。

诸如,倘使管道包括上边的级差:

{ $redact: { $cond: { if: { $eq: [ “$level”, 5 ] }, then: “$$PRUNE”,
else: “$$DESCEND” } } },

{ $match: { year: 2014, category: { $ne: “Z” } } }

优化程序能够在$redact阶段从前增加相同的$match阶段:

{ $match: { year: 2014 } },

{ $redact: { $cond: { if: { $eq: [ “$level”, 5 ] }, then: “$$PRUNE”,
else: “$$DESCEND” } } },

{ $match: { year: 2014, category: { $ne: “Z” } } }

$project + $skip 或$limit管道顺序优化

3.2本子新增

当管道顺序为$projec后跟$skip或$limit时,$skip或$limit会移动到$projec从前,

比如说,尽管管道包括上边包车型客车级差:

{ $sort: { age : -1 } },

{ $project: { status: 1, name: 1 } },

{ $limit: 5 }

在优化阶段,优化器将队列顺序改变为下边那样:

{ $sort: { age : -1 } },

{ $limit: 5 },

{ $project: { status: 1, name: 1 } }

这种优化为$sort +
$limit合并提供更多的火候,例如体系$sort + $limit。

1.4.3 管道合并优化

那一个优化阶段将2个管道阶段与它后面包车型客车管道阶段统一。一般地,合并发生在等级重新排序之后。

合并$sort + $limit

当$sort前面紧跟$limit时,优化程序能将$limit合并到$sort,这使得排序操作仅保留结果集中的前n条数据并处理它,n是钦命的限定,MongoDB只供给在内部存款和储蓄器中存款和储蓄n个条款。

当设置allowDiskUse
为true时同时n条数据已经超(英文名:jīng chāo)越了汇集内部存储器的范围,上边那种优化依然会被选择。

合并$limit + $limit

当 $limit末端紧跟另四个$limit时,八个等级统一为一个等级,合并后的限制值为两岸中幽微值。

例如,假使管道包括下边包车型客车级差:

{ $limit: 100 },

{ $limit: 10 }

第二个$limit等级被合并到第三个$limit等级中,合并后的限制值为100和第10中学细小的,即10。

{ $limit: 10 }

合并$skip + $skip

当 $skip前边紧跟另2个$skip时,多少个$skip合并为多个$skip,跳过的数额为双方之和。

例如,假如管道包罗下边包车型大巴级差:

{ $skip: 5 },

{ $skip: 2 }

其次个$skip被统一到第二个$skip中,合并后跳过的数额为5和2之和。

{ $skip: 7 }

合并$match + $match

当 $match前面紧跟另1个$match时,七个等级统一为3个结合使用$and的$match,跳过的数目为互相之和。

例如,假如管道包括上边包车型大巴级差:

{ $match: { year: 2014 } },

{ $match: { status: “A” } }

其次个$match被合并到首个$match中。

{ $match: { $and: [ { “year” : 2014 }, { “status” : “A” } ] } }

合并$lookup + $unwind

3.2本子新增

当$lookup之后紧跟$unwind并且$unwind 操作$lookup的字段,优化阶段能够将$unwind合并到$lookup中。那制止了创办较大的中间文书档案。

比如,借使管道包涵下边的级差:

{

  $lookup: {

    from: “otherCollection”,

    as: “resultingArray”,

    localField: “x”,

    foreignField: “y”

  }

},

{ $unwind: “$resultingArray”}

优化器将$unwind合并到$lookup中。借使运维聚合的时候使用explain 选项,输出的联结阶段为:
{

  $lookup: {

    from: “otherCollection”,

    as: “resultingArray”,

    localField: “x”,

    foreignField: “y”,

    unwinding: { preserveNullAndEmptyArrays: false }

  }

}

1.5例子

上边例子所示的有的行列可以选拔再度排序和合并优化。一般地,合并爆发在再度排序之后。

序列$sort + $skip + $limit

管道蕴涵$sort阶段,其后接$skip阶段,$skip阶段后接
$limit阶段

{ $sort: { age : -1 } },{ $skip: 10 },{ $limit: 5 }

率先,优化程序将$skip +
$limit转化为上面包车型大巴顺序:

{ $sort: { age : -1 } },

{ $limit: 15 },

{ $skip: 10 }

眼下的队列为$sort阶段后跟$limit阶段,管道能够合并那多少个进程以减掉排序阶段对内部存款和储蓄器的费用。

序列$limit + $skip + $limit +
$skip

1个管道包蕴了$limit和$skip交替出现的行列:

{ $limit: 100 },

{ $skip: 5 },

{ $limit: 10 },

{ $skip: 2 }

优化程序将{ $skip: 5 } 和{
$limit: 10 } 顺序反转,并附加限制数量:

{ $limit: 100 },

{ $limit: 15},

{ $skip: 5 },

{ $skip: 2 }

优化程序可以将多少个$limit合并,将四个$skip合并,结果为:

{ $limit: 15 },

{ $skip: 7 }

1.6 聚合管道限制

动用聚合命令有如下限制:

结果大小限制

2.6本子中变化

从2.6版本初阶,聚合命令(aggregate)能够回来二个游标或将结果存款和储蓄在联谊中。当重回游标只怕将结果存储到聚集中时,结果集中的每2个文书档案受限于BSON文书档案大小,方今BSON文书档案大小最大允许为16MB;如果别的1个文书档案的大小超过了那么些值,聚合命令将抛出一个荒谬。那些范围只效劳于重临的文书档案,在管道中被处理的文书档案有或者超越那么些阈值。从2.6起来,db.collection.aggregate()
方法私下认可再次回到游标。

假如不钦赐游标选项或许将结果存款和储蓄到聚集中,aggregate 命令归来2个BSON文书档案,文书档案有一个包蕴结果集的字段。文书档案的尺寸超过了BSON文书档案允许的最大值,聚合命令将抛出二个张冠李戴。

在更早的本子中,aggregate仅能回到二个富含结果集的BSON文书档案,假诺文书档案的分寸超越了BSON文书档案允许的最大值,聚合命令将抛出2个错误。

内部存储器限制

2.6本子中生成

管道阶段对内部存款和储蓄器的界定为100MB。如若某一品级选取的内部存款和储蓄器超越100MB,MongoDB
会抛出2个荒唐。为了能够处理大数据集,

行使allowDiskUse选项使聚合管道阶段将数据写入权且文件。

1.7会师管道和分片集合

会面管道帮助分片集合上的操作。

行为

3.2版本中的变化

假使聚合管道以$match开头,精确地同盟1个片键,整个聚合管道仅运维在十分到的分片上。在此之前的版本中,管道会被拆分,合并的做事要在主分片上达成。

对此要运维在几个分片上的聚众操作,尽管操作不须要周转在数据库的主分片上,这几个操作将会路由结果到自由分片来归并结果以幸免数据库主分片过载。

$out阶段和$lookup阶段需求周转在数据库主分片上。

优化

当把聚和管道分成多少个部分时,在考虑优化的情景下,拆分管道时保障每三个分片执行阶段数量尽量多。

要查看管道什么被拆分,使用db.collection.aggregate()和explain选项。

1.8 邮编数据集上的集聚操作

示范中选择集合zipcodes
,那一个集合能够从:http://media.mongodb.org/zips.json处获得。使用mongoimport将数据导入你的mongod 实例。

数据模型

集合zipcodes中的每一文书档案的体制如下:

{

  “_id”: “10280”,

  “city”: “NEW YORK”,

  “state”: “NY”,

  “pop”: 5574,

  “loc”: [

    -74.016323,

    40.710537

  ]

}

  • _id字段值为字符串格局的邮政编码。
  • city 字段值为都市名称。二个城市可有八个邮编,城市的不比恩平市邮编差别。
  • State字段值为七个假名的州名称缩写。
  • pop字段值为人口数量。
  • Loc字段值为用经纬度表示的方向。

aggregate()方法

aggregate() 方法运用聚合管道处理文书档案,输出聚合结果。贰个聚众管道由五个阶段组成,当文书档案经过聚众管道种种阶段时,管道处理进入当中的文档。

在mongo shell中,aggregate() 方法提供了对aggregate 的包装。

归来人口数量在1000万以上的州

上边包车型大巴汇集操作重临全部人口数在1000万以上的州:

db.zipcodes.aggregate( [

   { $group: { _id: “$state”, totalPop: { $sum: “$pop” } } },

   { $match: { totalPop: { $gte: 10*1000*1000 } } }] )

在这些事例中,聚合管道包括 $group阶段,其后跟$match阶段。

  • $group阶段依据state
    字段将zipcode
    集合分组,计算每一个州的totalPop字段值,输出结果为每一个州对应3个文书档案。

新的有关种种州的消息的文书档案包罗五个字段:_id
字段和totalPop字段。_id字段值是州的称谓,totalPop字段值是经总计后取得的外省的总人口数。为了总结那些值$group阶段采用$sum操作符计算每一种州的人口数。

  • 透过$group管道阶段后的在管道中的文书档案样式如下:

{

  “_id” : “AK”,

  “totalPop” : 550043

}

$match阶段过滤分组后的文档,仅输出这多少个totalPop值大于等于1000万的文书档案。$match阶段不会修改文书档案而是输出未修改的协作到的文书档案。

与聚集操作等价的SQL语句为:

SELECT state, SUM(pop) AS totalPop 

FROM zipcodes 

GROUP BY state 

HAVING totalPop >= (10*1000*1000)

回去每种州的都会人口平均值

上面包车型客车集聚操作重临各个州的城池人口平均值

db.zipcodes.aggregate( [

   { $group: { _id: { state: “$state”, city: “$city” }, pop: { $sum:
“$pop” } } },

   { $group: { _id: “$_id.state”, avgCityPop: { $avg: “$pop” } } }]

)

在那一个事例中,聚合操作包罗了五个$group阶段。

  • 率先个$group 阶段依据city和state字段组合将文书档案分组,$sum 表明式依据每一种组合总结人口数,并出口文书档案,每二个城市和州的咬合对应一个文书档案。

地点十三分阶段完毕后,管道中的文书档案样式为:
{

  “_id” : {

    “state” : “CO”,

    “city” : “EDGEWATER”

  },

  “pop” : 13154

}

  • 其次个$group阶段依照_id.state字段将文书档案分组(state字段在_id文书档案内),使用$avg表明式计算每一个城池人口的平均值(avgCityPop)并出口文书档案,每一个州对应贰个文书档案。

以此聚合操作再次来到文书档案类似于:

{

  “_id” : “MN”,

  “avgCityPop” : 5335

}

重回州中规模最大和纤维的都会

上面包车型大巴成团操作重临每种州人口数最多和最少的城市。

db.zipcodes.aggregate( [

   { $group:

      {

        _id: { state: “$state”, city: “$city” },

        pop: { $sum: “$pop” }

      }

   },

   { $sort: { pop: 1 } },

   { $group:

      {

        _id : “$_id.state”,

        biggestCity:  { $last: “$_id.city” },

        biggestPop:   { $last: “$pop” },

        smallestCity: { $first: “$_id.city” },

        smallestPop:  { $first: “$pop” }

      }

   },

 

  // the following $project is optional, and

  // modifies the output format.

 

  { $project:

    { _id: 0,

      state: “$_id”,

      biggestCity:  { name: “$biggestCity”,  pop: “$biggestPop” },

      smallestCity: { name: “$smallestCity”, pop: “$smallestPop” }

    }

  }]

)

在那一个聚合操作中蕴藏了多少个$group阶段,三个$sort阶段,3个$project阶段。

  • 首先个$group 阶段依照city和state字段组合将文书档案分组,$sum 表明式依照各个组合总计人口数(五个都市恐怕有多个邮编,因为1个城池的差别区有不相同的邮编),并出口文书档案,每3个城市和州的构成对应1个文书档案。这一个阶段文书档案类似于:

{

  “_id” : {

    “state” : “CO”,

    “city” : “EDGEWATER”

  },

  “pop” : 13154

}

  • $sort阶段依据pop字段的值为管道中的文书档案排序,顺序为从小到大;例如递增的相继。那个操作不会修改文书档案。
  • 其次个$group 阶段依据_id.state字段对当下已排序的文书档案分组(例如,state
    字段在_id文书档案中)并出口各样州对应的文书档案。

本条阶段为每一个州计算如下八个字段值:使用$last表明式,$group操作符成立biggestCity 和biggestPop字段,biggestPop字段值为最大的人口数,biggestCity值为biggestPop对应的都会称号。使用$first 表明式,$group操作符创立了smallestCity和smallestPop,smallestPop为最小的人口数,smallestCity为smallestPop对应的城池名称。

管道中那几个阶段的文书档案类似于:

{

  “_id” : “WA”,

  “biggestCity” : “SEATTLE”,

  “biggestPop” : 520096,

  “smallestCity” : “BENGE”,

  “smallestPop” : 2

}

最后的$project阶段将_id字段重命名为state
并将biggestCity, biggestPop, smallestCity,
和smallestPop移到嵌入式文书档案biggestCity 和

smallestCity中。

下边那么些聚合操作的结果类似于:

{

  “state” : “RI”,

  “biggestCity” : {

    “name” : “CRANSTON”,

    “pop” : 176404

  },

  “smallestCity” : {

    “name” : “CLAYVILLE”,

    “pop” : 45

  }

}

 

1.9 用户引用数据的汇合操作

数据模型

设若2个体育俱乐部有3个饱含users集合数据库,users集合中的文书档案包括用户的进入日期和喜好的位移,文书档案样式如下:

{

  _id : “jane”,

  joined : ISODate(“2011-03-02”),

  likes : [“golf”, “racquetball”]

}

{

  _id : “joe”,

  joined : ISODate(“2012-07-02”),

  likes : [“tennis”, “golf”, “swimming”]

}

文书档案规范化和排序

下边包车型地铁操作再次来到的文书档案中,用户名称转成大写并按字母逐一排序。操作如下:

db.users.aggregate(

  [

    { $project : { name:{$toUpper:”$_id”} , _id:0 } },

    { $sort : { name : 1 } }

  ])

Users集合中的全部文书档案都通过了管道,在管道中施行以下操作:

  • $project操作符:
  • 创建名为name的字段。
  • 利用$toUpper操作符将_id字段值转换来大写。然后将值存储在名为name
    的字段中。
  • 阻止_id字段。$project 操作符默许允许_id字段通过,除非显著地拦住。
  • $sort操作符依照name字段对结果实行排序。

聚拢操作重临结果为:

{

  “name” : “JANE”},{

  “name” : “JILL”},{

  “name” : “JOE”

}

重返根据加入时间排序后的用户名称

上面的聚集操作再次回到依据加入月份排序的用户名称,这种聚合操作有助于生成会员更新提示。

db.users.aggregate(

  [

    { $project :

       {

         month_joined : { $month : “$joined” },

         name : “$_id”,

         _id : 0

       }

    },

    { $sort : { month_joined : 1 } }

  ]

)

Users集合中的全数文书档案都因而了管道,在管道中履行以下操作:

  • $project操作符:
  • 创建几个字段month_joined
    和name。
  • 截留结果集中的id输出。$project 操作符暗中认可允许_id字段通过,除非分明地阻挠。
  • $month操作符将joined字段的值转换为以平头表示的月度。然后$project操作符将这个值钦命给month_joined字段。
  • $sort操作符依照month_joined字段对结果开始展览排序。

操作再次回到的结果为:

{

  “month_joined” : 1,

  “name” : “ruth”},{

  “month_joined” : 1,

  “name” : “harold”},{

  “month_joined” : 1,

  “name” : “kate”}{

  “month_joined” : 2,

  “name” : “jill”

}

 

归来种种月进入会员的总数

上边的操作体现了各类月有几个人变成会员。你可能能够使用这个聚集数据来设想是还是不是招聘新职员和工人和制定营销策略。

db.users.aggregate(

  [

    { $project : { month_joined : { $month : “$joined” } } } ,

    { $group : { _id : {month_joined:”$month_joined”} , number : {
$sum : 1 } } },

    { $sort : { “_id.month_joined” : 1 } }

  ]

)

users 集合中全数文书档案都通过管道,在管道中履行如下操作:

  • $project操作符制造了3个新字段month_joined。
  • $month操作符将joined字段的值转换为以平头表示的月份。然后$project操作符将这一个值钦点给month_joined字段。
  • $group操作符将全数文档按month_joined值分组,并盘算每种month_joined字段值对应几个文书档案。特别地,对于每一种唯一的

    month_joined值,$group创制了3个新的“每一个月”的文档,该文书档案包罗了八个字段:

  • _id字段,包涵1个嵌入式文书档案,嵌入式文书档案有1个month_joined字段。
  • number字段,那是二个新转变的字段。对每一个包括给定month_joined字段值的文书档案,$sum操作符将number字段值加1.
  • $sort操作符依据month_joine字段将$group操作符处理过的文档排序。

这一个聚和操作的结果为:

{

  “_id” : {

    “month_joined” : 1

  },

  “number” : 3},

{

  “_id” : {

    “month_joined” : 2

  },

  “number” : 9},

{

  “_id” : {

    “month_joined” : 3

  },

  “number” : 5}

再次来到各个最普遍的“爱好”

上边包车型地铁成团操作选出四个最广大“爱好”。那体系型的剖析有助于升高安顿。

db.users.aggregate(

  [

    { $unwind : “$likes” },

    { $group : { _id : “$likes” , number : { $sum : 1 } } },

    { $sort : { number : -1 } },

    { $limit : 5 }

  ]

)

users 集合中全部文书档案都因此管道,在管道中履行如下操作:

  • $unwind操作符将数组likes中的每三个因素分别,并为各样要素成立八个最初的作品档的新本子。

例如:

下边包车型大巴文书档案:

{

  _id : “jane”,

  joined : ISODate(“2011-03-02”),

  likes : [“golf”, “racquetball”]

}

$unwind操作符创制的文书档案为:

{

  _id : “jane”,

  joined : ISODate(“2011-03-02”),

  likes : “golf”

}

{

  _id : “jane”,

  joined : ISODate(“2011-03-02”),

  likes : “racquetball”

}

  • $group操作符依照likes字段值分组并盘算每组的数据。使用这几个音讯,$group创设含有八个字段的新文档:
  • _id字段,包含likes字段值。
  • number新生成的字段,对于富含给定likes字段值的各类文书档案$sum操作符将number加1。
  • $sort操作符依照number字段将文书档案顺序反转。
  • $limit 操作符限制结果集中仅包涵前五个文书档案。

{

  “_id” : “golf”,

  “number” : 33},

{

  “_id” : “racquetball”,

  “number” : 31},

{

  “_id” : “swimming”,

  “number” : 24},

{

  “_id” : “handball”,

  “number” : 19},

{

  “_id” : “tennis”,

  “number” : 18}

}

 —————————————————————————————–

转载与引用请证明出处。

时刻匆忙,水平有限,如有不当之处,欢迎指正。

 

相关文章