2013-03-01 50 views
2

我剛剛開始在Mongo中使用MapReduce,並使用組合鍵(日期,候選人)返回與該鍵相關聯的值的查詢(該候選人的總票數在那一天)。我實際上喜歡的是每個日期的累積票數。也就是說,對於每個日期/候選鍵,該值是該候選人在該日期之前和之前投下的所有選票的總和。如何在MongoDB中生成累計結果MapReduce

這是我的當前代碼:

示例輸入:

{ 
    "interaction" : { 
     "type" : "draft", 
     "parameters" : { 
      "value" : [ 
       { 
        "candidate" : 453510, 
        "votes" : 2 
       }, 
       { 
        "candidate" : 325786, 
        "votes" : 2 
       } 
      ] 
     } 
    }, 
    "created_at" : 1360796255 
} 

地圖:

var mapFn = function() { 
    var right = function(str, n) { 
    return str.substring(str.length, str.length - n); 
    } 
    var toDate = function(epochTimeSec) { 
    var d = new Date(1000 * epochTimeSec); 
    var yr = d.getYear() + 1900; 
    var mn = d.getMonth() + 1; 
    var dt = d.getDate(); 
    return '' + right('0000' + yr, 4) + '-' + right('00' + mn, 2) + '-' + right('00' + dt, 2); 
    } 

    for(var i=0; i<this.interaction.parameters.value.length; i++) 
    { 
    vote = this.interaction.parameters.value[i]; 
    var creationDate = toDate(this.created_at); 
    var votedCandidate = vote.candidate; 
    emit({date: creationDate, candidate: votedCandidate}, { quantity: candidate.quantity }); 
    } 
} 

減少:

var reduceFn = function(key, values) { 
    var sum = 0; 
    values.forEach(function(doc) { 
    sum += doc.quantity; 
    }); 
    return { quantity: sum }; 
} 

輸出:

db.collection_mr.drop(); 
db.collection.mapReduce(mapFn, reduceFn, { out: 'collection_mr' }); 

function printData(r) { 
    print(r._id.date + ", " + r._id.candidate + ", " + r.value.quantity); 
} 

db.collection_mr.find().forEach(printData); 

感謝您的幫助!

EDIT

響應於評論,我已經包括一個例子的輸入。澄清 - 上述代碼正確返回每個日期投下的所有選票的總和。但是,我想調整它,以便在每個日期返回在該日期之前或之前投下的所有選票。

要回答Asya Kamsky,這是要臨時手動運行,因此需要在輸入日期(可能不是當前日期)之前輸出所有數據。

+0

究竟是不是工作? – rompetroll 2013-03-01 18:59:55

+0

你能提供一個來自集合的示例文檔嗎?就收集累計結果而言 - 您計劃運行MR工作的頻率如何?每天獲得前一天的選票或類似的東西? – 2013-03-01 20:49:00

+0

感謝您的意見。我已經在上面添加了一個示例輸入並重申了我的問題。 – Serenthia 2013-03-04 10:44:17

回答

4

使用聚合框架而不是mapReduce可以更容易地解決問題。從manual摘錄:

MongoDB的聚合框架提供計算 聚合值,而無需使用一種手段地圖減少。雖然map-reduce 功能強大,但對於許多簡單的聚合任務而言,通常比完成或平均字段值更困難。

這aggregate命令返回您預期的結果:

// target date as unix timestamp, example: 2013-02-28T23:59:59) 
targetDate = Date.UTC(2013,1,28,23,59,59)/1000; // month -1 !! 

db.xx.aggregate([ 
    // select documents created_at up to target date 
    // note: this match uses an index, if defined on created_at 
    { $match: { 
     "created_at": { $lte: targetDate } 
    }}, 
    // unwind the "value" array 
    { $unwind: "$interaction.parameters.value" }, 
    // group by candidates, sum up votes 
    { $group: { 
     _id: "$interaction.parameters.value.candidate", 
     votes: { $sum: "$interaction.parameters.value.votes" } 
    }}, 
]) 

結果:

{ 
    "result" : [ 
     { 
      "_id" : 325786, 
      "votes" : 2 
     }, 
     { 
      "_id" : 453510, 
      "votes" : 2 
     } 
    ], 
    "ok" : 1 
}