2015-11-07 30 views
4

我有一系列的文檔在MongoDB中。一個示例doc將是MongoDB在前幾周的總收入爲每週的基礎

{ 
    createdAt: Mon Oct 12 2015 09:45:20 GMT-0700 (PDT), 
    year: 2015, 
    week: 41 
} 

想象一下,這些跨越一年中的所有星期,並且在同一周內可能會有很多。我想彙總它們的結果值是每週的總和以及前幾周所有文檔的總和。

所以,如果有第二是像10年的第一週和20,其結果可能是類似

[{ week: 1, total: 10, weekTotal: 10}, 
{ week: 2, total: 30, weekTotal: 20}] 

創建聚集找到weekTotal是很容易的。包括一個投影來顯示第一部分

db.collection.aggregate([ 
    { 
    $project: { 
     "createdAt": 1, 
     year: {$year: "$createdAt"}, 
     week: {$week: "$createdAt"}, 
     _id: 0 
    } 
    }, 
    { 
    $group: { 
     _id: {year: "$year", week: "$week"}, 
     weekTotal : { $sum : 1 } 
    } 
    }, 
]); 

但通過這個基於上週和前幾周的總和證明是棘手的。

回答

1

聚合框架無法執行此操作,因爲所有操作一次只能有效查看一個文檔或分組邊界。爲了做到這一點,「服務器」上你需要的東西,可使用全局變量,以保持「運行總計」,這意味着mapReduce代替:

db.collection.mapReduce(
    function() { 

     Date.prototype.getWeekNumber = function(){ 
      var d = new Date(+this); 
      d.setHours(0,0,0); 
      d.setDate(d.getDate()+4-(d.getDay()||7)); 
      return Math.ceil((((d-new Date(d.getFullYear(),0,1))/8.64e7)+1)/7); 
     }; 


     emit({ year: this.createdAt.getFullYear(), week: this.createdAt.getWeekNumber() }, 1); 
    }, 
    function(values) { 
     return Array.sum(values); 
    }, 
    { 
     out: { inline: 1 }, 
     scope: { total: 0 }, 
     finalize: function(value) { 
      total += value; 
      return { total: total, weekTotal: value } 
     } 
    } 
) 

如果你能在運行存在的活「客戶」,那麼你通過聚合結果需要循環和類似的總結匯總:

var total = 0; 

db.collection.aggregate([ 
    { "$group": { 
     "_id": { 
      "year": { "$year": "$createdAt" }, 
      "week": { "$week": "$createdAt" } 
     }, 
     "weekTotal": { "$sum": 1 } 
    }}, 
    { "$sort": { "_id": 1 } } 
]).map(function(doc) { 
    total += doc.weekTotal; 
    doc.total = total; 
    return doc; 
}); 

這是它是否是很有道理的給你,這是否需要在服務器上發生或所有的問題客戶端。但是由於聚合管道沒有這樣的「全局變量」,所以你可能不應該把它看作任何進一步的處理,而無需輸出到另一個集合。