从db table(Rails)

时间:2016-04-29 11:39:25

标签: ruby-on-rails algorithm

上下文 尝试在db表中为每个created_at天生成一个包含1个元素的数组。每个元素是points天的记录中created_at(整数)列的平均值。 稍后将绘制图表,以显示每天的平均点数。

结果: 我已经成功地做到了这一点,但感觉就像生成所需结果的代码量不必要。

代码:

def daily_avg
    # get all data for current user
    records = current_user.rounds

    # make array of long dates
    long_date_array = records.pluck(:created_at)

    # create array to store short dates
    short_date_array = []

    # remove time of day
    long_date_array.each do |date|
        short_date_array << date.strftime('%Y%m%d')
    end 

    # remove duplicate dates
    short_date_array.uniq!

    # array of avg by date
    array_of_avg_values = []

    # iterate through each day
    short_date_array.each do |date|
        temp_array = []

        # make array of records with this day
        records.each do |record|
            if date === record.created_at.strftime('%Y%m%d')
                temp_array << record.audio_points
            end
        end
        # calc avg by day and append to array_of_avg_values
        array_of_avg_values << temp_array.inject(0.0) { |sum, el| sum + el } / temp_array.size
    end
    render json: array_of_avg_values
end

问题: 我认为这是一个需要通过大量应用程序解决的常见extraction问题,所以我想知道是否有一个已知的可重复模式来解决这样的问题?

或者更优化的方法来解决这个问题?

(我只是一个初级开发人员,所以你能分享的任何建议都会受到赞赏!)

3 个答案:

答案 0 :(得分:2)

是的,当您可以直接使用SQL来执行此操作时,这是很多不必要的事情(我假设您的应用中有一个名为Round的类):

class Round

  DAILY_AVERAGE_SELECT = "SELECT 
      DATE(rounds.created_at) AS day_date,
      AVG(rounds.audio_points) AS audio_points
    FROM rounds
    WHERE rounds.user_id = ?
    GROUP BY DATE(rounds.created_at) 
"

  def self.daily_average(user_id)
    connection.select_all(sanitize_sql_array([DAILY_AVERAGE_SELECT, user_id]), "daily-average")
  end

end

直接进入数据库将比在Ruby中执行此操作更快(并且还包括更少的代码)。正如您现在所做的那样。

答案 1 :(得分:0)

我建议你做这样的事情:

grouped =
records.order(:created_at).group_by do |r|
   r.created_at.strftime('%Y%m%d')
end

首先,您可以在第一次近似中生成适当的SQL,然后将created_at字段的结果记录转换为日期。

points =
grouped.map do |(date, values)|
   [ date, values.reduce(0.0, :audio_points) / values.size ]
end.to_h

# => { "1-1-1970" => 155.0, ... }

然后,您通过数组重新映射分组哈希值,以audio_points计算平均值。

答案 2 :(得分:-1)