MongoDB 聚合


MongoDB除了基本的查詢功能,還提供了很多強大的聚合工具,其中簡單的可計算集合中的文檔個數,

復雜的可利用MapReduce做復雜數據分析.

 

1.count

count返回集合中的文檔數量

db.refactor.count()

不管集合有多大,都能很快的返回文檔數量.

可以傳遞查詢,MongoDB會計算查詢結果的數量

db.refactor.count({"username":"refactor"})

但是增加查詢條件會使count變慢.

 

2.distinct

distinct用來找出給定鍵的所有不同值.使用時必須指定集合和鍵.

如:

db.runCommand({"distinct":"refactor","key":"username"})

 

 3.group

group先選定分組所依據的鍵,MongoDB將會將集合依據選定鍵值的不同分成若干組.然后可以通過聚合每一組內的文檔,

產生一個結果文檔.

如:

db.runCommand(
{
  "group":
  {
    "ns":"refactor",
    "key":{"username":true},
    "initial":{"count":0},
    "$reduce":function(doc,prev)
    {
      prev.count++;
    },
    "condition":{"age":{"$gt":40}}
  }
}
)

   "ns":"refactor",

指定要進行分組的集合
    "key":{"username":true},

指定文檔分組的依據,這里是username鍵,所有username鍵的值相等的被划分到一組,true為返回鍵username的值
    "initial":{"count":0},

每一組reduce函數調用的初始個數.每一組的所有成員都會使用這個累加器.
    "$reduce":function(doc,prev){...}

每個文檔都對應的調用一次.系統會傳遞兩個參數:當前文檔和累加器文檔.

"condition":{"age":{"$gt":40}}

這個age的值大於40的條件

 

4.使用完成器

完成器用於精簡從數據庫傳到用戶的數據.group命令的輸出一定要能放在單個數據庫相應中.

"finalize"附帶一個函數,在數組結果傳遞到客戶端之前被調用一次.

db.runCommand(
  {
    "group":
    {
      "ns":"refactor",
      "key":{"username":true},
      "initial":{"count":0},
      "$reduce":function(doc,prev)
      {
        prev.count++;
      },
      "finalize":function(doc)
      {
        doc.num=doc.count;
        delete doc.count;
      }
    }
  }
)

finalize能修改傳遞的參數也能返回新值.

 

5.將數組作為鍵使用

有些時候分組所依據的條件很復雜,不僅是一個鍵.比如要使用group計算每個類別有多篇博客文章.由於有很多作者,

給文章分類時可能不規律的使用了大小寫.所以,如果要是按類別名來分組,最后"MongoDB"和"mongodb"就是不同的組.

為了消除這種大小寫的影響,就要定義一個函數來確定文檔所依據的鍵.

定義分組要用到$keyf

db.runCommand(
 {
  "group":
   {
    "ns":"refactor",
    "$keyf":function(doc){return {"username":doc.username.toLowerCase()}},
    "initial":{"count":0},
    "$reduce":function(doc,prev)
       {
        prev.count++;
       }
   }
 }
)

 

6.MapReduce

count,distinct,group能做的事情MapReduce都能做.它是一個可以輕松並行化到多個服務器的聚合方法.它會

拆分問題,再將各個部分發送到不同機器上,讓每台機器完成一部分.當所有機器都完成時候,再把結果匯集起來形成

最終完整的結果.

MapReduce需要幾個步驟:

1.映射,將操作映射到集合中的每個文檔.這個操作要么什么都不做,要么 產生一個鍵和n個值.

2.洗牌,按照鍵分組,並將產生的鍵值組成列表放到對應鍵中.

3.化簡,把列表中的值 化簡 成一個單值,這個值被返回.

4.重新洗牌,直到每個鍵的列表只有一個值為止,這個值就是最終結果.

MapReduce的速度比group慢,group也很慢.在應用程序中,最好不要用MapReduce,可以在后台運行MapReduce

創建一個保存結果的集合,可以對這個集合進行實時查詢.

 

找出集合中的所有鍵

MongoDB沒有模式,所以並不知曉每個文檔有多少個鍵.通常找到集合的所有鍵的做好方式是用MapReduce.

在映射階段,想得到文檔中的每個鍵.map函數使用emit 返回要處理的值.emit會給MapReduce一個鍵和一個值.

這里用emit將文檔某個鍵的記數(count)返回({count:1}).我們為每個鍵單獨記數,所以為文檔中的每一個鍵調用一次emit,

this是當前文檔的引用:

map=function(){
  for(var key in this)
  {
    emit(key,{count:1})
  }
};

這樣返回了許許多多的{count:1}文檔,每一個都與集合中的一個鍵相關.這種有一個或多個{count:1}文檔組成的數組,

會傳遞給reduce函數.reduce函數有兩個參數,一個是key,也就是emit返回的第一個值,另一個參數是數組,由一個或者多個

對應鍵的{count:1}文檔組成.

reduce=function(key,emits){
  total=0;
  for(var i in emits){
    total+=emits[i].count;
  }
  return {count:total};
}

reduce要能被反復被調用,不論是映射環節還是前一個化簡環節.reduce返回的文檔必須能作為reduce的

第二個參數的一個元素.如x鍵映射到了3個文檔{"count":1,id:1},{"count":1,id:2},{"count":1,id:3}

其中id鍵用於區別.MongoDB可能這樣調用reduce:

>r1=reduce("x",[{"count":1,id:1},{"count":1,id:2}])

{count:2}

>r2=reduce("x",[{"count":1,id:3}])

{count:1}

>reduce("x",[r1,r2])

{count:3}

reduce應該能處理emit文檔和其他reduce結果的各種集合.

如:

mr=db.runCommand(
  {
  "mapreduce":"refactor",
  "map":map,
  "reduce":reduce,
  "out":{inline:1}
  }
)

或:

db.refactor.mapReduce(map,reduce,{out:{inline:1}})

"timeMillis" : 5,//操作花費的時間
"counts" : {
"input" : 10,//發往到map函數的文檔個數
"emit" : 40,//在map函數中emit被調用的次數
"reduce" : 4,//在map函數中reduce被調用的次數
"output" : 4//結果集合中創建的文檔數量.
},

1.mapreduce是根據map函數里調用的emit函數的第一個參數來進行分組的
2.僅當根據分組鍵分組后一個鍵匹配多個文檔,才會將key和文檔集合交由reduce函數處理

注意MongoDB 1.8版本以上,必須指明 out 參數

否則會報如下錯誤:

"assertion" : "'out' has to be a string or an object",
"assertionCode" : 13606,

 

MapReduce中的其他鍵

mapreduce,map,reduce這三個鍵是必須的,MapReduce命令還有其他的可選鍵

finalize:函數

將reduce的結果發送給這個鍵,這是處理過程的最后一步

keeptemp:布爾值

連接關閉時,臨時結果是否保存

output:字符串

結果集合的名字,設定該項則隱含着keeptemp:true

query:文檔

會在發往map函數前,先用指定條件過濾文檔

sort:文檔

會在發往map函數前先給文檔排序

limit:整數

發往map函數文檔的最大數量

scope:文檔

javascript代碼中要用到的變量

verbose:布爾值

是否產生更加信息的服務器日志 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM