MapReduce應該算是MongoDB操作中比較複雜的了,自己開始理解的時候還是動了動腦子的,所以記錄在此!
命令文法:詳細看
db.runCommand( { mapreduce : 字串,集合名, map : 函數,見下文 reduce : 函數,見下文 [, query : 文檔,發往map函數前先給過渡文檔] [, sort : 文檔,發往map函數前先給文檔排序] [, limit : 整數,發往map函數的文檔數量上限] [, out : 字串,統計結果儲存的集合] [, keeptemp: 布爾值,連結關閉時臨時結果集合是否儲存] [, finalize : 函數,將reduce的結果送給這個函數,做最後的處理] [, scope : 文檔,js代碼中要用到的變數] [, jsMode : 布爾值,是否減少執行過程中BSON和JS的轉換,預設true] //註:false時 BSON-->JS-->map-->BSON-->JS-->reduce-->BSON,可處理非常大的mapreduce,
//true時BSON-->js-->map-->reduce-->BSON [, verbose : 布爾值,是否產生更加詳細的伺服器日誌,預設true] });
測試資料:
現在我要統計同一age的name,也就是像如下的結果:
{age:0,names:["name_6","name_12","name_18"]}
{age:1,names:["name_1","name_7","name_13","name_19"]}
......
第一步是寫映射(Map)函數,可以簡單的理解成分組吧~
var m=function(){
emit(this.age,this.name);
}
emit的第一個參數是key,就是分組的依據,這是自然是age了,後一個是value,可以是要統計的資料,下面會說明,value可以是JSON對象。
這樣m就會把送過來的資料根據key分組了,可以想象成如下結構:
第一組
{key:0,values: ["name_6","name_12","name_18"]
第二組
{key:1,values: ["name_1","name_7","name_13","name_19"]
......
組中的key其實就是age的值了,values是個數組,數組內的成員都有相同的age!!。
第二步就是簡化了,編寫reduce函數:
var r=function(key,values){
var ret={age:key,names:values};
return ret;
}
reduce函數會處理每一個分組,參數也正好是我們想像分組裡的key和values。
這裡reduce函數只是簡單的把key和values封裝了一下,因為不用怎麼處理就是我們想要的結果了,然後返回一個對象。對象結構正好和我們想象的相符!:
{age:對應的age,names:[名字1,名字2..]}
最後,還可以編寫finalize函數對reduce的傳回值做最後處理:
var f=function(key,rval){
if(key==0){
rval.msg="a new life,baby!";
}
return rval
}
這裡的key還是上面的key,也就是還是age,rval是reduce的傳回值,所以rval的一個執行個體如:{age:0,names:["name_6","name_12","name_18"]},
這裡判斷 key 是不是 0 ,如果是而在 rval 對象上加 msg 屬性,顯然也可以判斷 rval.age==0,因為 key 和 rval.age 是相等的嘛!!
這裡其他的選項就不說了,一看就知道。
運行:
db.runCommand({
mapreduce:"t",
map:m,
reduce:r,
finalize:f,
out:"t_age_names"
}
)
結果匯入到 t_age_names 集合中,查詢出來正是我想要的結果,看一下文檔的結構,不難發現,_id 就是 key,value 就是處理後的傳回值。