3

既存の Rails アプリを移行して MongoDB (Mongoid を使用) を使用していますが、MySQL でできるように集計を行う方法を理解するのに苦労しています。

以前はSELECT DATE(created_at) AS day, SUM(amount) AS amount GROUP BY day、次のようなテンプレートでループできるコレクションを返すようなものがありました。

:day => '2011-03-01', :amount => 55.00 
:day => '2011-03-02', :amount => 45.00
etc...

Mongoidでそれを行う方法を知っている人はいますか? モデルは非常に単純です。

class Conversion
  include Mongoid::Document
  include Mongoid::Timestamps

  field :amount,      :type => Float, :default => 0.0
  ...
  # created_at generated automatically, standard Rails...
end

ありがとう!

-アビシャイ

4

2 に答える 2

6

残念ながら、それはあなたが思っているよりも少し難しいです。

私の理解では、Mongoid 自体は 1 つのクエリでのグループ化と追加をサポートしていません。そのためには、MongoDB ドライバーで直接 map/reduce を行う必要があります。あなたが持っているものと同様のデータ構造でこの例を実行しましたが、翻訳中にいくつかのエラーが発生する可能性があります。問題がある場合はお知らせください。修正を試みます。

まず、map 関数と reduce 関数を定義する必要があります。これらは JavaScript 文字列として保存する必要があります。

map = "function(){ emit(new Date(this.created_at.getYear(), this.created_at.getMonth(), this.created_at.getDate()), {amount: this.amount}); };"
reduce = "function(key, values){ var sum = 0; values.forEach(function(doc){ sum += doc.amount; }); return {amount: sum};};"

map_reduce次に、コレクションを直接呼び出します。この場合は次のようになります。

Conversion.collection.map_reduce(map, reduce).find.to_a

次のようなハッシュの配列を返します。

[{"_id"=>Sat Dec 13 13:00:00 UTC 0110, "value"=>{"amount"=>55.0}}, {"_id"=>Sat Jan 17 13:00:00 UTC 0111, "value"=>{"amount"=>45.0}}] 
于 2011-03-25T03:40:19.557 に答える
0

Mongoid には、簡単な計算のためのショートカットもいくつかあります。

以下を任意のスコープに追加できます。

.max(:age)
.min(:quantity)
.sum(:total)

これは、アプリケーションとmongoのカーソルをループするため、 m/r ほど速くないことに注意してください。ただし、結果セットがそれほど大きくない場合は、適切なオプションです

ソースは次のとおりです: https://github.com/mongoid/mongoid/blob/2.4.0-stable/lib/mongoid/contexts/enumerable.rb

また、今後の集約フレームワークにもご期待ください: http://www.mongodb.org/display/DOCS/Aggregation+Framework

于 2012-04-26T15:52:07.160 に答える