13

MongoDB と mongoid を使い始めたばかりです。私が抱えている最大の問題は、マップ/リデュース機能を理解して、非常に基本的なグループ化などを実行できるようにすることです。

次のようなモデルがあるとしましょう:

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 関数は、これらの操作を内部的に行う DB にフィードされると思います。アクティブなレコードから来るこれらの新しい概念は少し奇妙です。

Rails 4.0、Ruby 1.9.3、Mongoid 4.0.0、Heroku (mongolab) の 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

ただし、このような単純な操作には、map reduce ではなく Aggregation を使用することをお勧めします。これを行う方法は次のとおりです。

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

結果はマップを縮小した場合とほぼ同じになり、記述するコードははるかに少なくなります。

于 2013-10-10T12:54:32.823 に答える