目前的MongoDB在進行複雜的資料統計計算時都需要寫MapReduce來實現,包括在SQL中比較常用的group by查詢也需要寫一個reduce才能實現,這是比較麻煩的。在MongoDB2.1中,將會引入一套全新的資料統計計算架構,讓使用者更方便的進行統計操作。
下面我們就來看看幾個新的操作符:
$match
$match的作用是過濾資料,通過設定一個條件,將資料進行篩選過濾,例子:
db.runCommand({ aggregate : "article", pipeline : [ { $match : { author : "dave" } }]});
這相當於將article這個collection中的記錄進行篩選,篩選條件是author屬性值為dave,其作用其實相當於普通的find命令,如:
> db.article.find({ author : "dave" });
所以,那這個命令有什麼用呢?與find不同,find的結果是直接作為最終資料返回,而$match只是pipeline中的一環,它篩選的結果資料可以再進行下一級的統計操作。
$project
$project命令用於設定資料的篩選欄位,就像我們SQL中select需要的欄位一樣。例子:
db.runCommand({ aggregate : "article", pipeline : [ { $match : { author : "dave" } }, { $project : { _id : 0,author : 1, tags : 1 }}]});
上面就是將所有author為dave的記錄的author和tags兩個欄位取出來。(_id:0 表示去掉預設會返回的_id欄位)
其實上面這個功能也能用我們平時用的find命令來實現,如:
> db.article.find({ author : "dave" }, { _id : 0, author : 1, tags : 1);$unwind
$unwind命令很神奇,他可以將某一個為array類型欄位的資料拆分成多條,每一條包含array中的一個屬性。
比如你使用下面命令添加一條記錄:
db.article.save( { title : "this is your title" , author : "dave" , posted : new Date(4121381470000) , pageViews : 7 , tags : [ "fun" , "nasty" ] , comments : [ { author :"barbara" , text : "this is interesting" } , { author :"jenny" , text : "i like to play pinball", votes: 10 } ], other : { bar : 14 }});
這裡面tags欄位就是一個array。下面我們在這個欄位上應用$unwind操作
db.runCommand({ aggregate : "article", pipeline : [ { $unwind : "$tags" }]});
上面命令的意思就是按tags欄位來拆分,此命令執行的結果如下:
{ "result" : [ { "_id" : ObjectId("4eeeb5fef09a7c9170df094b"), "title" : "this is your title", "author" : "dave", "posted" : ISODate("2100-08-08T04:11:10Z"), "pageViews" : 7, "tags" : "fun", "comments" : [ { "author" : "barbara", "text" : "this is interesting" }, { "author" : "jenny", "text" : "i like to play pinball", "votes" : 10 } ], "other" : { "bar" : 14 } }, { "_id" : ObjectId("4eeeb5fef09a7c9170df094b"), "title" : "this is your title", "author" : "dave", "posted" : ISODate("2100-08-08T04:11:10Z"), "pageViews" : 7, "tags" : "nasty", "comments" : [ { "author" : "barbara", "text" : "this is interesting" }, { "author" : "jenny", "text" : "i like to play pinball", "votes" : 10 } ], "other" : { "bar" : 14 } } ], "ok" : 1}
我們可以看到,原來的tags欄位是一個包含兩個元素的數組,通過$unwind命令後,被拆分成兩條記錄,每一條記錄的tags欄位是原來數組中的一個元素。
$group
$group命令比較好理解,功能就是按某一個key將key值相同的多條資料群組織成一條。
比如我們使用下面命令再往article這個collection中寫入一條記錄,這時候我們就有兩條記錄了:
db.article.save( { title : "this is some other title" , author : "jane" , posted : new Date(978239834000) , pageViews : 6 , tags : [ "nasty" , "filthy" ] , comments : [ { author :"will" , text : "i don't like the color" } , { author :"jenny" , text : "can i get that in green?" } ], other : { bar : 14 }});
我們可以先用上面的$unwind按tags將記錄拆成多條,然後再將記錄按tags欄位重新組織,將同一個tag對應的所有author放在一個array中。只需要像下面這樣寫:
db.runCommand({ aggregate : "article", pipeline : [ { $unwind : "$tags" }, { $group : {_id : "$tags", count : { $sum : 1 },authors : { $addToSet : "$author" } }}]});
這時候你就能得到如下結果了
{ "result" : [ { "_id" : "filthy", "count" : 1, "authors" : [ "jane" ] }, { "_id" : "fun", "count" : 1, "authors" : [ "dave" ] }, { "_id" : "nasty", "count" : 2, "authors" : [ "jane", "dave" ] } ], "ok" : 1}
上面是2.1版本將會推出的一些新的統計類命令的介紹,在易用性方面它們提供給我們很多便利,但是MongoDB MapReduce的最大硬傷,單個mongod中無法並存執行,貌似還是沒有解決。雖然其命令中採用了pipeline 的組織模式,但是貌似還是完全串列且分降段完成的。