1. 程式人生 > >MongoDB——aggregate聚合優化技巧

MongoDB——aggregate聚合優化技巧

此文章簡要介紹MongoDB聚合的技巧,第二條的技巧思路也可以適用於MapReduce統計過程。

按天統計資料


db.test.aggregate([
    {"$project" : { "newTime" : {"$add" : ["$originalTime" , 1000 * 60 * 60 * 8] } , "newAccountTime" : 1, "otherField" : 1} },
    {"$group" : {
        "_id" : {
            "year" : {"$year" : "$newTime" }, "month" : {"$month" : "$newTime"} , "day" : {"$dayOfMonth" : "$newTime"} ,
                "timeStr" : {"$substr" : ["$newTime", 0, 10 ] } , "otherField" : "$otherField"
            }
        }
    },
    // ....
    {"$sort" : {"year" : 1, "month" : 1, "day" : 1}}
])

將按不同的key聚合語句,合併為一條

其思路也可以用到MapReduce處理流程。 
在某些情況下,需要統計每個比賽模式的玩家綜合資料,也需要統計每個玩家在不同比賽模式的資料。 
例如,有”排位模式“、”大亂鬥模式“、”休閒模式“等。需要統計各個遊戲模式下,玩家參與數、勝率等資料。這樣統計需要以gameId作為聚合的key。 
同時,也需要統計各個玩家在不同“排位模式”、“休閒模式”的參與次數、勝率等。這樣統計需要以玩家的userId作為聚合的key。 
解決思路:

  1. 按gameId和userId進行group。
  2. 對上一步的gameId進行group,同時將userId push 到數組裡面。這樣就得到第一個要求的資料,且將玩家的資訊儲存下來了。
  3. 對上一步的陣列用unwind進行拆分
  4. 對上一步的拆分結果的userId進行group。這樣每個userId聚合的結果也帶了遊戲模式的統計結果。
  5. 進行過濾處理。

經測試,這樣只讀取了一次資料庫,中間過程對記憶體的要求比較高,需要開啟allowDiskUse選項,一次聚合比兩次聚合效率高很多。

參考程式碼:


global.ldb.collection("grandLog").aggregate([
    // ....
        {"$group" : {"_id" :{"gameId" : "$gameId", "userId" : "$userId"} , "otherField" : "$otherField" } },
        {"$group" : {
            "_id" : "$_id.gameId", "userCount" : {"$sum" : 1} ,
                "userInfo" : {"$push" : {"userId" : "$_id.userId" ,"otherField" : "$otherField"} }
            }
        },
        {"$unwind" : "$userInfo"},
        {"$group" : {"_id" :"$userInfo.userId", "gameId" : {"$push" : "$_id"},
            "userCount" : {"$push" : "$userCount" } }
        }
], {"allowDiskUse" : true } );
也可以根據業務資料將group的兩個步驟顛倒。