2013-10-10 3 views
11

Я только что начал с MongoDB и mongoid. Самая большая проблема, с которой я столкнулась, заключается в понимании функциональности карты/сокращения, чтобы иметь возможность выполнять некоторые основные группировки и т. Д.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 карту уменьшить, чтобы получить коллекцию этих объектов сгруппированы по полю sdate? И чтобы получить сумму возрастов тех, кто разделяет одно и то же поле sdate?

Я знаю об этом: http://mongoid.org/en/mongoid/docs/querying.html#map_reduce Но это как-то помогло бы увидеть это применительно к реальному примеру. Куда идет этот код, в модели, я думаю, необходим объем и т. Д.

Я могу сделать простой поиск с помощью mongoid, получить массив и вручную построить все, что мне нужно, но я думаю, что уменьшение карты - вот путь здесь , И я полагаю, что эти функции js, упомянутые на странице mongoid, отправляются в БД, что делает эти операции внутренне. Исходя из активной записи, эти новые концепции немного странны.

Я нахожусь на Rails 4.0, Ruby 1.9.3, Mongoid 4.0.0, MongoDB 2.4.6 на Heroku (mongolab), хотя у меня есть локальный 2.0, который я должен обновить.

Спасибо.

+0

См. Здесь: http://docs.mongodb.org/manual/core/map-reduce/#MapReduce-Outputoptions – user2503775

+0

Спасибо. Я должен был больше обратить внимание на документы mongodb, чем на mongoid. Это намного лучше показано на странице mongodb, которую вы добавили. – Pod

ответ

18

Принимая примеры от 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"}}}]) 

и результат будет практически идентичен с картой уменьшается, и Вы написали бы намного меньше кода.

+0

Makis благодарит за помощь! – Pod

Смежные вопросы