使用MongoDB / Mongoid和计算字段聚合函数

时间:2011-03-24 10:27:39

标签: ruby-on-rails mongodb mapreduce mongodb-query mongoid

我正在迁移现有的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

谢谢!

-Avishai

2 个答案:

答案 0 :(得分:5)

不幸的是,它比你想象的要难一点。

我的理解是,Mongoid本身不支持在一个查询中进行分组和添加,这样做 - 您需要直接使用MongoDB驱动程序进行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}}] 

答案 1 :(得分:0)

Mongoid还有一些简单计算的快捷方式:

您可以将以下内容添加到任何范围:

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

注意,这不会像m / r一样快,因为它在应用程序和mongo中循环通过游标。但是如果你的结果集不那么大,那么这是一个不错的选择

以下是来源:https://github.com/mongoid/mongoid/blob/2.4.0-stable/lib/mongoid/contexts/enumerable.rb

请继续关注即将推出的聚合框架:http://www.mongodb.org/display/DOCS/Aggregation+Framework