-
Notifications
You must be signed in to change notification settings - Fork 465
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
Please provide a way to preload ancestry #440
Comments
Duplicate of #140 |
@Morred Do you have nodes C and D? I think that falls under wanting |
I'm looking into improving |
@kbrock As far as I can see in the readme, there's only Otherwise, yes, having a
If that seems in any way useful, I'm happy to dive into the code and attempt a PR, or otherwise I'll let you have a go at it! |
I guess, for now best way to prevent N+1 query is to add associasion like this: has_many :child_models, class_name: 'Model', foreign_key: 'parent_id' You can include child_models in your request with .includes(:child_models) |
parent_id is not in the database. So at the current moment, this is not possible. I have looked into providing ways of getting the parent_id and ancestor_ids in sql form, but it was very unweildy. Currently there is no way of getting |
Hi all. Here is my solution to get parent in one SQL query: # == Schema Information
#
# Table name: teams
#
# id :uuid not null, primary key
# ancestry :text
# name :string
class Team < ApplicationRecord
has_ancestry(orphan_strategy: :restrict, primary_key_format: %r{\A[\w\-]+(/[\w\-]+)*\z})
def self.with_parents
joins("INNER JOIN teams AS parents on UUID(SUBSTR(teams.ancestry, STRPOS(teams.ancestry, '/') + 1)) = parents.id")
end
end Data: root1 = Team.create!(company_id: company_id, name: 'root1', id: '361da83d-5c20-4112-b1f6-2ccda3eafe05')
t1 = Team.create!(company_id: company_id, name: 't1', parent: root1, id: '5b243c45-d589-4ea0-8446-0d8b25839009') And finally request [25] pry(main)> Team.where(id: '5b243c45-d589-4ea0-8446-0d8b25839009').select('teams.id AS id, parents.id AS parent_id').with_parents.first.attributes
=> {"id"=>"5b243c45-d589-4ea0-8446-0d8b25839009", "parent_id"=>"361da83d-5c20-4112-b1f6-2ccda3eafe05"} Which issues one SQL query: 2020-12-15 21:36:35.959934 D [23584:12260] ActiveRecord::Base -- Team Load (3.6ms) SELECT teams.id AS id, parents.id AS parent_id FROM "teams" INNER JOIN teams AS parents on UUID(SUBSTR(teams.ancestry, STRPOS(teams.ancestry, '/') + 1)) = parents.id WHERE "teams"."id" = $1 ORDER BY "teams"."id" ASC LIMIT $2 [["id", "5b243c45-d589-4ea0-8446-0d8b25839009"], ["LIMIT", 1]] I've searched how to make it with But later decided to use simpler and most obvious way (because we do not have much data) like this: teams = Team.where(id: […])
parent_ids = teams.map(&:parent_id)
parents = Team.find(parent_ids) which issues two SQL queries. ...
found = parents.find { |parent| team.parent_id == parent.id }
... Still interested if is there a way to create custom relations has_one, belongs_to, has_many with custom SQL?! |
rails 1 and 2 used to allow us to specify find sql. I know this doesn't address your problem, but you may be able to reduce data load on teams. I'm trying to remove our use of |
of note, we do have methods for children_sql, I hope this may provide some use for now. |
Suppose I have these models:
So each person belongs to an area, which are arranged as a tree. Now if I want to print a list with a set of people and the area they belong to, I get N+1 queries:
It would be great to have a way to tell rails to preload the ancestors of a set of records.
The text was updated successfully, but these errors were encountered: