Има ли причина (различна от вече споменатата дата), поради която не бихте използвали вградените възможности за групови функции в 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
Тази партида ми изглежда малко претрупана:мисля, че може да бъде по-кратка и по-чиста. Бих проучвал изграждането на хеш или структура, вместо да оставам в масиви.
[1] Не казвам, че не използвайте SQL - възникват ситуации, в които ActiveRecord не може да генерира най-ефективната заявка и вие се връщате към find_by_sql
. Това е добре, трябва да е така, но мисля, че трябва да се опитате да го използвате само в краен случай.