Working on a report/metrics page and I need to optimize the queries as much as I can so I am using find_by_sql for efficiency.
One of my queries is doing some aggregate functions where I return a count and some sums. I'm assigning the results of this query into instance variables for a model.
I have working code, but the code scares me. I have read the official Ruby/Rails docs on the methods used, but I still think there's something wrong with what I'm doing.
def initialize(args)
@loans_count = stats.loans_count
@total_fees_in_cents = stats.total_fees_in_cents
@total_amount_in_cents = stats.total_amount_in_cents
end
def stats
@stats ||= find_stats
end
def find_stats
if single_year?
loans = Loan.find_by_sql(["SELECT count(*) as loans_count, sum(amount) as total_amount_in_cents, sum(fee) as total_fees_in_cents FROM loans WHERE account_id = ? AND year = ? LIMIT 1", @account_id, @year]).first
else
loans = Loan.find_by_sql(["SELECT count(*) as loans_count, sum(amount) as total_amount_in_cents, sum(fee) as total_fees_in_cents FROM loans WHERE account_id = ? LIMIT 1", @account_id]).first
end
# Store results in OpenStruct for ease of access later on
OpenStruct.new(
loans_count: loans.loans_count || 0,
total_fees_in_cents: loans.total_fees_in_cents || 0,
total_amount_in_cents: loans.total_amount_in_cents || 0
)
end
Concerns
find_by_sql
is supposed to return an array; the SQL will always return a row, even if no matches are found (null values, but a valid row). However, is there a reason I shouldn't call.first
on the returned array? I'm afraid of hitting[].first => nil
in some case I didn't anticipate.- Is my method of "caching" the result using the
stats
method an appropriate method of only querying the DB 1 time? It seems like a lot of code and methods just to get some aggregate data.