I'm trying to return the 12 monthly data, however I keep getting that nil can't be coerced into Integer, this happen when starting with mapping from 0..11 because I use months.ago to group the data which it starts to count from the current month.
def yearly_results
return [] unless user.results.order(id: :desc).where('created_at >= ?', 30.days.ago)
attributes = [:skin_age, :skin_age_adjusted, :skin_tightness, :purity, :hyperpigmentation_face_score]
results = []
# We create a Hash with every months attributes and values
(0..11).map do |months_ago|
month_results = grouped_by_months[months_ago.months.ago.strftime('%Y%m')] || []
months_with_attr = month_results.reduce({}) do |key, value|
attributes.each do |attr_name|
key[attr_name] ||= 0
key[attr_name] = value.send(attr_name)
end
key
end
if months_with_attr.present?
months_with_attr.transform_values do |value|
value.to_f / month_results.count
end
end
results << months_with_attr.presence
end
results.reverse
end
This is the error that I keep getting.
*** TypeError Exception: nil can't be coerced into Integer
nil
CodePudding user response:
Given you want to use as little SQL as possible i´d propose the following:
attributes = [:skin_age, :skin_age_adjusted, :skin_tightness, :purity, :hyperpigmentation_face_score]
user.results.order(id: :desc).where('created_at >= ?', 30.days.ago)
.group_by{|result| result.created_at.month }
.transform_values{|results_per_month| attributes.map{|attr| [attr, results_per_month.map(&attr).reduce(&: ).to_f / results_per_month.count] }.to_h }
CodePudding user response:
So if i get this right, you want to calculate the average per month.
I´d suggest to do this with SQL:
attributes = [:skin_age, :skin_age_adjusted, :skin_tightness, :purity, :hyperpigmentation_face_score]
# Get the average with SQL (for Postgres)
averages = user.results.order(id: :desc).where('created_at >= ?', 30.days.ago)
.group("date_trunc('month', created_at)").select("date_trunc('month', created_at) AS month", attributes.map{|attr| "AVG(#{attr}) AS average_#{attr}" })
# Then group by month
averages.group_by{|res| res['month'].month }
.transform_values{|results_per_month| results_per_month.map{|result_per_month| result_per_month.without('id', 'month') } }
# => {1 => [{"average_skin_age" => 30, ...}], 2 => [{"average_skin_age" => 32, ...}],}
