Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Suggestion] Add support for eager loading optionally #138

Closed
rafacoello opened this issue Nov 8, 2021 · 4 comments
Closed

[Suggestion] Add support for eager loading optionally #138

rafacoello opened this issue Nov 8, 2021 · 4 comments

Comments

@rafacoello
Copy link
Contributor

rafacoello commented Nov 8, 2021

Hello. I would like to ask you if there is an specific reason why not to optionally allow eager load of relationships on locate/locate_many.
I mean something like this:

def locate_many(gids, options = {})
  models_and_ids = gids.collect { |gid| [ gid.model_class, gid.model_id ] }
  ids_by_model = models_and_ids.group_by(&:first)
  loaded_by_model = Hash[ids_by_model.map do |model, ids|
    [ model, find_records(model, ids.map(&:last), includes: options[:includes], ignore_missing: options[:ignore_missing]).index_by { |record| record.id.to_s } ]
  end]

  models_and_ids.collect { |(model, id)| loaded_by_model[model][id] }.compact
end

private
 def find_records(model_class, ids, options)
    if options[:ignore_missing]
      model_class.includes(options[:includes]).where(id: ids)
    else
      model_class.includes(options[:includes]).find(ids)
    end
  end
def 

It would be not exactly like that code, but well, it's an idea.

Thanks in advance

@rafaelfranca
Copy link
Member

Can you explain how that would be used and why?

@rafacoello
Copy link
Contributor Author

rafacoello commented Nov 24, 2021

Hello @rafaelfranca
ActiveRecord supports eager load (using includes method). This is useful in some cases that you know you will be calling a lot the relationships of a model, so you end having an N+1 queries issue.

E.g.

users = User.find([ 1, 2 ]) # This generates a query SELECT * FROM users WHERE id IN (1, 2)
users.first.posts # This generates a query SELECT * FROM posts WHERE user_id = 1
users.first.posts # This generates a query SELECT * FROM posts WHERE user_id = 1 again.

In the other hand:

users = User.includes(:posts).find([ 1, 2 ]) # This generates both queries (SELECT * FROM users WHERE id IN (1, 2)) and (SELECT * FROM posts WHERE user_id IN (1, 2))
users.first.posts # No query
users.last.posts # No query 

If we had this feature here, we could do something like GlobalID::Locator.locate_many([ user_gid_1, user_gid_2 ], {includes: :posts}) which would eager load the posts.

I know that can be done with a custom Locator (which I already did for my case) but I thought that having that option could be useful to anyone as it is very generic.

@rafaelfranca
Copy link
Member

Makes sense. Do you want to open a PR for it?

@rafacoello
Copy link
Contributor Author

Sure. Thanks! @rafaelfranca

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants