13

我刚刚开始使用 MongoDB 和 mongoid。我遇到的最大问题是理解 map/reduce 功能以便能够进行一些非常基本的分组等。

可以说我有这样的模型:

class Person
  include Mongoid::Document
  field :age, type: Integer
  field :name
  field :sdate
end

该模型将产生如下对象:

#<Person _id: 9xzy0, age: 22, name: "Lucas", sdate: "2013-10-07">
#<Person _id: 9xzy2, age: 32, name: "Paul", sdate: "2013-10-07">
#<Person _id: 9xzy3, age: 23, name: "Tom", sdate: "2013-10-08">
#<Person _id: 9xzy4, age: 11, name: "Joe", sdate: "2013-10-08">

有人可以展示如何使用 mongoid map reduce 来获取按 sdate 字段分组的那些对象的集合吗?并获得共享相同 sdate 字段的人的年龄总和?

我知道这一点:http: //mongoid.org/en/mongoid/docs/querying.html#map_reduce 但不知何故,将它应用于一个真实的例子会有所帮助。在我猜的模型中,该代码在哪里,是需要的范围等。

我可以用 mongoid 进行简单的搜索,获取数组并手动构造我需要的任何东西,但我猜 map reduce 是这里的方式。我想这些在 mongoid 页面上提到的 js 函数被提供给在内部进行这些操作的数据库。来自主动记录的这些新概念有点奇怪。

我在 Heroku(mongolab)上使用 Rails 4.0、Ruby 1.9.3、Mongoid 4.0.0、MongoDB 2.4.6,尽管我有本地 2.0 应该更新。

谢谢。

4

1 回答 1

22

http://mongoid.org/en/mongoid/docs/querying.html#map_reduce中获取示例并根据您的情况调整它们并添加注释以进行解释。

map = %Q{
  function() {
    emit(this.sdate, { age: this.age, name : this. name }); 
      // here "this" is the record that map
      // is going to be executed on
  }  
}

reduce = %Q{
  function(key, values) {   
           // this will be executed for every group that
           // has the same sdate value
    var result = { avg_of_ages: 0 };
    var sum = 0;    // sum of all ages
    var totalnum = 0  // total number of people
    values.forEach(function(value) {
      sum += value.age;    
    });
    result.avg_of_ages = sum/total   // finding the average
    return result;
  }
}

results = Person.map_reduce(map, reduce) //You can access this as an array of maps

first_average = results[0].avg_of_ages

results.each do |result|
   // do whatever you want with result
end

虽然我建议你使用聚合而不是映射减少这样一个简单的操作。这样做的方法如下:

 results = Person.collection.aggregate([{"$group" => { "_id" => {"sdate" => "$sdate"}, 
                                                "avg_of_ages"=> {"$avg" : "$age"}}}])

并且结果将与 map reduce 几乎相同,并且您将编写更少的代码。

于 2013-10-10T12:54:32.823 回答