I am trying to get top 5 movies that have the most purchases. So I came up with this query:
@movies = Movie.joins(:purchases)
.select('movies.id, movies.name, count(purchases.id) as purchases_count')
.group('movies.id').order('purchases_count desc').limit(5)
Then I display the top 5 movies in my view along with their purchase type count(purchases have 2 types, "partial" or "full").
<% @movies.each do |t| %>
<%= t.name %>
Partial purchase:
<%= t.purchases.where(type: "partial").count %>
Full purchase:
<%= t.purchases.where(type: "full").count %>
<% end %>
This is working, however, I am afraid this causes N+1 queries due to select count from movies. Some solutions I can think of includes:
1) Is there a way to filter purchase count in select
method? for example something like this:
@movies = Movie.joins(:purchases)
.select('movies.id, movies.name, count(purchase.where(type: "partial")) as purchases_partial_count, count(purchases.id) as purchases_count')
2) Can I extract the ids from @movies
and write another query such as:
@purchases = Movie.find_by(@movies_ids).includes(:purchases)
and use length
to replace count
in my views?
I am open to other better solutions, thanks and any help will be appreciated!