MongoDB - Mongoid的map reduce基本操作

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函数被提供给内部执行这些操作的数据库。对于习惯了active record的我来说,这些新概念有点奇怪。

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

谢谢。


请参见此处:http://docs.mongodb.org/manual/core/map-reduce/#MapReduce-Outputoptions - user2503775
谢谢。我应该更关注mongodb文档而不是mongoid。您添加的mongodb页面上展示得更好。 - Pod
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

虽然我建议您使用聚合而不是map reduce来进行这样简单的操作。操作方式如下:

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

使用这种方法,结果几乎与 MapReduce 相同,而你需要编写的代码要少得多。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接