如何使用Mongoid和Rails对结果进行分组?

时间:2014-08-19 20:22:58

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

我有一个使用Mongoid连接到MongoDB的模型事件:

class Event
  include Mongoid::Document
  include Mongoid::Timestamps

  field :user_name,   type: String
  field :action,      type: String
  field :ip_address,  type: String

  scope :recent,  -> { where(:created_at.gte => 1.month.ago) }    
end

通常当我使用ActiveRecord时,我可以做类似的事情来分组结果:

@action_counts  = Event.group('action').where(:user_name =>"my_name").recent.count

我得到的格式如下:

{"action_1"=>46, "action_2"=>36, "action_3"=>41, "action_4"=>40, "action_5"=>37}

使用Mongoid做同样事情的最佳方法是什么?

提前致谢

1 个答案:

答案 0 :(得分:2)

我认为你必须使用map / reduce来做到这一点。请查看此SO问题以获取更多详细信息:

Mongoid Group By or MongoDb group by in rails

否则,您只需使用group_by中的Enumerable方法即可。效率较低,但除非你有数十万份文件,否则它应该可以解决问题。

编辑:在这种情况下使用map / reduce的示例

我对它并不熟悉,但通过阅读文档和玩游戏,我无法重现你想要的完全相同的哈希,但试试这个:

def self.count_and_group_by_action
  map = %Q{
    function() {
      key = this.action;
      value = {count: 1};
      emit(key, value);
      # emit a new document {"_id" => "action", "value" => {count: 1}}
      # for each input document our scope is applied to
    }
  }

  # the idea now is to "flatten" the emitted documents that
  # have the same key. Good, but we need to do something with the values
  reduce = %Q{
    function(key, values) {
      var reducedValue = {count: 0};
      # we prepare a reducedValue
      # we then loop through the values associated to the same key,
      # in this case, the 'action' name
      values.forEach(function(value) {
        reducedValue.count += value.count; # we increment the reducedValue - thx captain obvious
      });
      # and return the 'reduced' value for that key,
      # an 'aggregate' of all the values associated to the same key
      return reducedValue;
    }
  }

  self.map_reduce(map, reduce).out(inline: true)
  # we apply the map_reduce functions
  # inline: true is because we don't need to store the results in a collection
  # we just need a hash
end

所以当你打电话时:

Event.where(:user_name =>"my_name").recent.count_and_group_by_action

应该返回类似的内容:

[{ "_id" => "action1", "value" => { "count" => 20 }}, { "_id" => "action2" , "value" => { "count" => 10 }}]

免责声明:我不是mongodb也不是mongoid专家,我的例子基于我在参考的SO问题和Mongodb / Mongoid在线文档中找到的内容,任何使这更好的建议都将受到赞赏。

资源:

http://docs.mongodb.org/manual/core/map-reduce/ http://mongoid.org/en/mongoid/docs/querying.html#map_reduce

Mongoid Group By or MongoDb group by in rails