2011-03-24 3 views
3

Я переношу существующее приложение Rails для использования MongoDB (с Mongoid), и у меня возникли проблемы с выяснением того, как делать агрегации, как вы можете делать с MySQL.Совокупные функции с MongoDB/Mongoid и вычисленными полями

Раньше у меня было что-то вроде SELECT DATE(created_at) AS day, SUM(amount) AS amount GROUP BY day, который будет возвращать коллекцию, вы можете перебрать в шаблоне, например так:

:day => '2011-03-01', :amount => 55.00 
:day => '2011-03-02', :amount => 45.00 
etc... 

Кто-нибудь знает, как сделать это в Mongoid? Модель довольно проста:

class Conversion 
    include Mongoid::Document 
    include Mongoid::Timestamps 

    field :amount,  :type => Float, :default => 0.0 
    ... 
    # created_at generated automatically, standard Rails... 
end 

Спасибо!

-Avishai

ответ

5

К сожалению, это немного сложнее, чем вы могли бы подумать.

Мое понимание заключается в том, что сам Mongoid не поддерживает группировку и добавление в один запрос, чтобы сделать это - вам нужно будет сделать карту/уменьшить непосредственно с помощью драйвера MongoDB. Я проверил этот пример с аналогичной структурой данных с тем, что у вас есть, но во время перевода может быть несколько ошибок, если у вас возникнут какие-либо проблемы, сообщите мне, и я попытаюсь внести в него изменения.

Прежде всего вам необходимо определить вашу карту и уменьшить функции. Они должны храниться как строки JavaScript.

map = "function(){ emit(new Date(this.created_at.getYear(), this.created_at.getMonth(), this.created_at.getDate()), {amount: this.amount}); };" 
reduce = "function(key, values){ var sum = 0; values.forEach(function(doc){ sum += doc.amount; }); return {amount: sum};};" 

Затем вы звоните map_reduce непосредственно на сбор, в данном случае:

Conversion.collection.map_reduce(map, reduce).find.to_a 

Который возвращает массив хэшей, как следующее:

[{"_id"=>Sat Dec 13 13:00:00 UTC 0110, "value"=>{"amount"=>55.0}}, {"_id"=>Sat Jan 17 13:00:00 UTC 0111, "value"=>{"amount"=>45.0}}] 
+0

Это на самом деле работает! Немного больше боли для использования, чем стандартные запросы стиля ActiveRecord, потому что вы должны получить результаты как «результат ['_ id'] ['value'] ['amount']', но довольно круто :-) – Avishai

0

Mongoid также имеет несколько сокращений для простых вычислений:

Вы можете добавить следующие действия в любой scop е:

.max(:age) 
.min(:quantity) 
.sum(:total) 

Примечание это не будет так быстро, как м/р для него перебирает курсор в приложении против в Монго. Но если ваш результирующий набор не такой большой, его хороший вариант

Вот источник: https://github.com/mongoid/mongoid/blob/2.4.0-stable/lib/mongoid/contexts/enumerable.rb

Также следите за предстоящей рамках агрегирования: http://www.mongodb.org/display/DOCS/Aggregation+Framework

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

  • Нет связанных вопросов^_^