MongoDB的簡單學習8-聚合操做

在MongoDB中,有兩種方式計算聚合:Pipeline 和 MapReduce。Pipeline查詢速度快於MapReduce,可是MapReduce的強大之處在於可以在多臺Server上並行執行復雜的聚合邏輯。MongoDB不容許Pipeline的單個聚合操做佔用過多的系統內存,若是一個聚合操做消耗20%以上的內存,那麼MongoDB直接中止操做,並向客戶端輸出錯誤消息。html

一,使用 Pipeline 方式計算聚合

Pipeline 方式使用db.collection.aggregate()函數進行聚合運算,運算速度較快,操做簡單,可是,Pipeline方式有兩個限制:單個聚合操做消耗的內存不能超過20%,聚合操做返回的結果集必須限制在16MB之內。mongodb

建立示例數據,在集合 c5中插入1000條doc,每一個doc中有三個field:idx,name 和 age。bash

for(i=0;i<10000;i++)
{ 
  db.c5.insert({"idx":i,name:"user "+i,age:i%90});
};

1 、使用$match 管道符過濾collection中doc,使符合條件的doc進入pipeline,可以減小聚合操做消耗的內存,提升聚合的效率。ide

db.c5.aggregate({$match:{age:{$lte:25}}});

2 、使用$project 管道符,使用doc中的部分field進入下級pipeline函數

db.c5.aggregate(
{$match:{age:{$lte:25}}}, 
{$project:{age:1,idx:1,_id:0}} 
);

project 管道符的做用是選擇字段,重命名字段,派生字段。spa

在$project 管道符中,field:1/0,表示選擇/不選擇 field;將無用的字段從pipeline中過濾掉,可以減小聚合操做對內存的消耗。code

3 、對字段重命名,產生新的字段htm

引用符$,格式是:"$field",表示引用doc中 field 的值,若是要引用內嵌 doc中的字段,使用 "$field1.filed2",表示引用內嵌文檔field1中的字段:field2的值。blog

示例,新建一個field:preIdx,其值和idx 字段的值是相同的。排序

db.c5.aggregate(
{$match:{age:{$lte:25}}}, 
{$project:{age:1,"preIdx":"$idx",idx:1,"_id":0}} 
);

4.派生字段

在$project中,對字段進行計算,根據doc中的字段值和表達式,派生一個新的字段。

示例,preIdx是根據當前doc的idx 減1 獲得的

db.c5.aggregate(
{$match:{age:{$lte:25}}}, 
{$project:
     {
    age:1,
    "preIdx":{$subtract:["$idx",1]},
    idx:1,
    "_id":0}
     } 
);

在$project 執行算術運算的操做符:+($add),*($multiply),/($divide),%($mod),-($subtract)。

對於字符數據,$substr:[expr,start,length]用於求子字符串;

                       $concat:[expr1,expr2,,,exprn],用於將表達式鏈接在一塊兒;

                       $toLower:expr 和 $toUpper:expr用於返回expr的小寫或大寫形式。

5.分組操做

使用$group將doc按照特定的字段的值進行分組,$group將分組字段的值相同的doc做爲一個分組進行聚合計算。若是沒有$group 管道符,那麼全部doc做爲一個分組。對每個分組,都能根據業務邏輯須要計算特定的聚合值。

分組操做和排序操做都是非流式的運算符

流式運算符是指:只要有新doc進入,就能夠對doc進行處理,

非流式運算符是指:必須等收到全部的文檔以後,才能對文檔進行處理。

分組運算符的處理方式是等接收到全部的doc以後,才能對doc進行分組,而後將各個分組發送給pipeline的下一個運算符進行處理。

//至關於 select age,count(*) where age <=25 group by age;
db.c5.aggregate(
{$match:{age:{$lte:25}}}, 
{$project:{age:1,"preIdx":{$subtract:["$idx",1]},idx:1,"_id":0}} ,
{$group:{"_id":"$age",count:{$sum:1}}}
);

//對於分組後的數量處理 //至關於 select age,count(*) where age <=25 group by age having count(*) >= 112;
db.c5.aggregate(
{$match:{age:{$lte:25}}}, 
{$project:{age:1,"preIdx":{$subtract:["$idx",1]},idx:1,"_id":0}} ,
{$group:{"_id":"$age",count:{$sum:1}}},
{$match:{count:{$gte:112}}} //分組後的數量大於等於112的
);

若是分組字段有多個,按照 age 和 age2 進行分組,這樣作僅僅是爲了演示,在實際的產品環境中,可使用更多的字段用來分組。

db.c5.aggregate(
{$match:{age:{$lte:25}}}, 
{$project:{age:1,"preIdx":{$subtract:["$idx",1]},idx:1,"_id":0}} ,
{$group:{"_id":{age:"$age",age2:"$age"},count:{$sum:1}}}
)

 

2、參考

http://www.runoob.com/mongodb/mongodb-aggregate.html

http://www.javashuo.com/article/p-zzfjmamr-gx.html

相關文章
相關標籤/搜索