Rails 3.0.3应用程序(卡在Dreamhost共享服务器上)。
我有一个页面显示根据一个模型的数据子集计算的平均值。
现在,每个平均值都是单独计算的,如下所示:
从视图中,我使用Devise身份验证提供的current_user
帮助程序来调用位于用户模型中的平均方法,如下所示:
<%= current_user.seven_day_weight_average %>
<%= current_user.fourteen_day_weight_average %>
<%= current_user.thirty_day_weight_average %>
以下是用户模型中的公共方法和平均方法:
def seven_day_weight_average
calculate_average_weight(7)
end
def fourteen_day_weight_average
calculate_average_weight(14)
end
def thirty_day_weight_average
calculate_average_weight(30)
end
. . .
private
def calculate_average_weight(number_days)
temp_weight = 0
weights_array = self.weights.find_all_by_entry_date(number_days.days.ago..Date.today)
unless weights_array.count.zero?
weights_array.each do |weight|
temp_weight += weight.converted_weight
end
return (temp_weight/weights_array.count).round(1).to_s
else
return '0.0'
end
end
这看起来效率不高 - 每次计算的平均值都会查询数据库。
如何使用一个数据库查询计算并使这些平均值可用于页面?
答案 0 :(得分:2)
您可以在过去30天内缓存一组转换后的权重(假设30是最大天数),如下所示:
def calculate_average_weight(number_days)
@converted_weights ||= weights.where("entry_date > ?", 30.days.ago).group_by(&:entry_date).sort_by do |date,weights|
date
end.collect do |date,weights|
weights.collect(&:converted_weight)
end
weights_during_period = @converted_weights[0..number_days-1].flatten
weights_during_period.sum / weights_during_period.length
end
说明:
首先,||=
获取或设置@converted_weights
(即除非它是零或假,否则不要设置它)。这确保只有一个db命中。接下来,我们会在30天前找到所有权重,并按日期分组。这将返回一个[date, weights]
数组,我们按日期排序。然后我们收集每个日期的转换权重,因此最终得到:[weights on day 1], [weights on day 2], ...
。
现在,计算:我们存储的值跨越weights_during_period
中数组的天数。我们将值展平并计算平均值。