Rails:如何处理来自一个模型的许多数据子集?

时间:2012-01-19 16:08:56

标签: ruby-on-rails ruby-on-rails-3

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

这看起来效率不高 - 每次计算的平均值都会查询数据库。

如何使用一个数据库查询计算并使这些平均值可用于页面?

1 个答案:

答案 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中数组的天数。我们将值展平并计算平均值。