Есть ли причина (кроме уже упомянутой даты), почему бы вам не использовать возможности встроенной функции группы в ActiveRecord? Вы, кажется, обеспокоены «постобработкой», о которой я не думаю, что действительно стоит беспокоиться.
Вы находитесь в Rails, поэтому вам, вероятно, следует сначала поискать решение Rails [1]. Моей первой мыслью было бы сделать что-то вроде
Product.average(:sales_price, :group => "DATE(created_at)", :conditions => ["merchant_id=?", 1])
, который ActiveRecord превратил в SQL, который вы описали. Если предположить, что между Продавцом и Продуктом существует объявленная has_many
связь, то вам, вероятно, будет лучше использовать ее, поэтому что-то вроде:
ave_prices = Merchant.find(1).products.average(:sales_price, :group => "DATE(created_at)")
(Я надеюсь, что ваше описание модели как "products_sold" является некоторой ошибкой транскрипции, кстати - если нет, вы несколько не согласны с именами классов!)
После всего этого вы вернулись к тому, с чего начали, но попали туда более обычным способом Rails (а Rails действительно ценит соглашения!). Теперь нам нужно заполнить пробелы.
Я предполагаю, что вы знаете свой диапазон дат, скажем, он определен как все даты от from_date
до to_date
.
date_aves = (from_date..to_date).map{|dt| [dt, 0]}
Это создает полный список дат в виде массива. Нам не нужны даты, когда мы получили среднее значение:
ave_price_dates = ave_prices.collect{|ave_price| ave_price[0]} # build an array of dates
date_aves.delete_if { |dt| ave_price.dates.index(dt[0]) } # remove zero entries for dates retrieved from DB
date_aves.concat(ave_prices) # add the query results
date_aves.sort_by{|ave| ave[0] } # sort by date
Эта партия выглядит немного загроможденной для меня: я думаю, что она может быть более краткой и чистой. Я бы исследовал создание Hash или Struct, а не оставался бы в массивах.
[1] Я не говорю, не используйте SQL - случаются ситуации, когда ActiveRecord не может сгенерировать наиболее эффективный запрос, и вы возвращаетесь к find_by_sql
. Это нормально, это должно быть так, но я думаю, что вы должны пытаться использовать это только в качестве крайней меры.