A
A
Anton Ivanov2015-03-23 16:31:24
ruby
Anton Ivanov, 2015-03-23 16:31:24

How to make eager loading when grouping?

Hello.
There are Purchase, Shop and Category models.
The goal is to get all the stores where purchases were made with the total amount of purchases.
Purchase.group(:shop).sum(:amount)
returns a Hash with the correct values ​​(shop object and amount)
But, at the same time, when I want to get the category of the store, then for each call to shop.category there is a request to the database.
I tried to do like this:

Purchace.group(:shop).includes(shop: [:category]).sum(:amount)

but nothing has changed.
At the sampling stage, two queries are executed to the database: 1 - to get grouped rows from the purchases table, 2 - to get data from all the stores that were present in the selection. I would like to have a third request - to get all categories of stores.
The models are described like this:
class Shop < ActiveRecord::Base
  belongs_to :category
  belongs_to :city
  has_many :purchases
end

class Category < ActiveRecord::Base
  has_many :shops
end

class Purchase < ActiveRecord::Base
  belongs_to :user
  belongs_to :shop
end

is it possible to do what i want?
Thanks in advance

Answer the question

In order to leave comments, you need to log in

2 answer(s)
V
vsuhachev, 2015-03-23
@vsuhachev

Try preload, it looks like includes misunderstands what you want
Read more here

A
Anton Ivanov, 2015-03-23
@Fly3110

I'm starting to think that this is impossible... Since in calculate.rb, in the execute_grouped_calculation method, there is such a block:

if association
        key_ids     = calculated_data.collect { |row| row[group_aliases.first] }
        key_records = association.klass.base_class.find(key_ids)
        key_records = Hash[key_records.map { |r| [r.id, r] }]
      end

that is, for calculation, after the request itself, rails receives only those records that match the first field of those for which the grouping
includes and preload add join to the first request, but since these fields are not in the select (and when adding nothing happens there), then when accessing the category, a request to the database is made again.
I will still try, but apparently after the request I will have to collect all the shop.category_id myself and make a request for them myself.
As a result, I did this:
purchases = user.purchases.select('shop_id, sum(count)').group(:shop_id)
shop_ids = purchases.collect do |purchase| purchase.shop_id end
shops = Shop.includes(:category).find(shop_ids)

But I still think there must be a better way to do it.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question