2013-01-08 81 views
0

我是新來的MongoDb,並有一個工作(我想)MapReduce或聚合。MongoDb聚合或mapreduce的發票統計?

我有這種格式的文檔的「發票」集合:

{ 
    date: 'some unix timestamp', 
    total: 12345, 
    paid: true 
} 

我需要個月(一月至十二月)爲列,每年可爲一排的總金額顯示錶在該單元中的月份(分爲付費和未付費)。像這樣:

 |  Jan  |  Feb  | ... 
2013 | 1,222/200 | 175/2,122 | ... 
... 

你能幫助我得到mongo命令嗎? 也許我最好寫一些JS代碼在mongo中執行?

+0

我的意思並不是苛刻,但如果你自己寫一個堅實的嘗試,然後尋求幫助而不是要求社區爲你寫信,它會更好。從聚合框架開始,除非您想將結果保留在自己的集合中。 – JohnnyHK

+0

@JohnnyHK,我完全同意你的看法。我真的是一個通過示例學習的人,我無法找到一個體面的例子來獲取基本的語法。 與此同時,我得到了一些工作,最終在我自己的答案。現在的問題是,這是否應該採用其他方法來完成,也許是聚合。 我發現mapreduce語法非常簡單直接。 –

+0

如果你喜歡mapreduce的語法,那麼堅持下去,除非它的性能不足。聚合框架通常更快。 – JohnnyHK

回答

4

我現在已經找到了一個使用MapReduce的解決方案。這裏是從PHP使用:

$map = new MongoCode(' 
    function() { 
     var d = new Date(this.date*1000); 
     emit({y: d.getFullYear(), m: d.getMonth()}, { 
      total: this.total, 
      notPaid: this.paid ? 0 : this.total, 
      count: 1 
     }); 
    }; 
'); 

$reduce = new MongoCode(' 
    function(month, values) { 
     result = { total: 0, notPaid: 0, count: 0 }; 
     for (var i = 0; i < values.length; i++) { 
      result.total += values[i].total; 
      result.notPaid += values[i].notPaid; 
      result.count += values[i].count; 
     } 
     return result; 
    }; 
'); 

$result = $db->command(array(
    'mapreduce' => 'invoices', 
    'map' => $map, 
    'reduce' => $reduce, 
    'out' => 'temp' 
)); 

echo $result['timeMillis']; 

現在結果是在「臨時」收集,每月一個文件。它可以被優化或增強?

+0

+1看起來不錯。做得很好! – JohnnyHK

+0

通過map/reduce解決這個問題的極好例子。看到我的答案爲聚合框架解決方案(這可能會快得多)。 –

3

你可以用這樣的聚合框架做到這一點:

db.invoices.aggregate([ 
    { 
     "$project" : { 
      "yr" : { 
       "$year" : "$date" 
      }, 
      "mo" : { 
       "$month" : "$date" 
      }, 
      "total" : 1, 
      "unpaid" : { 
       "$cond" : [ 
        "$paid", 
        0, 
        "$total" 
       ] 
      } 
     } 
    }, 
    { 
     "$group" : { 
      "_id" : { 
       "y" : "$yr", 
       "m" : "$mo" 
      }, 
      "total" : { 
       "$sum" : "$total" 
      }, 
      "unpaid" : { 
       "$sum" : "$unpaid" 
      } 
     } 
    } 
]) 

您可以在年底漂亮使輸出使用其他$project$sort來訂購吧,但是這是基本功能的核心它。

+0

謝謝。爲什麼它比mapreduce更快?是否有可能使用我的日期爲unix時間戳的例子? –

+0

看來,目前聚合框架$項目不支持將長時間存儲的unix時間戳直接轉換爲日期類型(這是$ year和$ month期望值)。你仍然可以做到這一點,但它會很糟糕和令人費解 - 它基本上需要使用帶有{$ cond:[{$ lt:「$ date」,ISODate(「2012-01-02T00:00:00」))的$項目。 valueOf()},「2012年1月」,{$ cond:... etc} ...將所有時間戳的範圍映射到合適的「年 - 月」字符串中,然後您可以對其進行分組。 –

+2

它比map/reduce快得多,因爲它在服務器上本地運行 - map reduce必須產生一個JavaScript shell來運行代碼,並將數據從BSON轉換爲JSON等等。 –