简体   繁体   中英

Rails Eager Load Identifiers in has_many Association

Say I have the following models:

class Category < ActiveRecord::Base
    has_and_belongs_to_many :items
end

class Item < ActiveRecord::Base
    has_and_belongs_to_many :categories
end

I'm building an endpoint that retrieves all items, where each item should be coupled with the array of category IDs it belongs to. An example result would be:

[
    {
        name: 'My Item',
        category_ids: [1, 2, 3]
    },
    // more items...
]

With this configuration, I'm able to call item.category_ids on each record which results in the SQL that I want, which looks like SELECT categories.id FROM categories INNER JOIN categories_items ... WHERE categories_items.item_id = $1 .

However, that obviously results in an N+1 - and I can't seem to find a way to do this now in an eager load. What I'm looking to do is get a list of items, and just the ID of the categories that they're in, by eager loading the category_ids field of each Item (although, if there's another way to accomplish the same using eager loading I'm okay with that as well)

Edit to explain difference from the duplicate:

I'm looking to see if it's possible to do two this in two separate queries. One that fetches items, and one that fetches category IDs. The items table is relatively wide, I'd prefer not to multiply the number of rows returned by the number of categories each item has - if possible.

Using a join model instead of has_and_belongs_to_many will allow you to query the join table directly instead (without hacking out a query yourself):

class Category < ActiveRecord::Base
  has_many :item_categories
  has_many :items, through: :item_categories
end

class Item < ActiveRecord::Base
  has_many :item_categories
  has_many :categories, through: :item_categories
end

class ItemCategory
  belongs_to :item
  belongs_to :category
end

Note that the table naming scheme for has_many through: is different - instead of items_categories its item_categories . This is so that the constant lookup will work correctly (otherwise rails looks for Items::Category as the join model!) - so you will need a migration to rename the table.


items = Item.all
category_ids = ItemCategory.where(item_id: items.ids).pluck(:category_id)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM