I have a self-referential association like this:
class User
belongs_to :parent_user, class_name: "User"
has_many :child_users, class_name: "User", foreign_key: :parent_user_id
end
When I get a list of users, I would like to be able to eager-load the child_users
association, but I only need the id
column from it. I need to be able to do something like this without causing n 1 queries, and preferably without having to load all of the other data in this model:
users = User.preload(:child_users)
users.map(&:child_user_ids)
The above works to limit the query to two queries instead of n 1, but I'm loading a lot of full objects into memory that I would prefer to avoid when I only care about the id
itself on those child assocations.
CodePudding user response:
You don't want eager loading which is for loading models. You want to select an aggregate. This isn't something the ActiveRecord query interface handles so you'll need to use SQL strings or Arel and use the correct function for your DB.
For example:
# This is for Postgres, use JSON_ARRAYAGG on MySQL
User.left_joins(:child_users)
.select(
"users.*",
'json_agg("child_users_users".id) AS child_ids'
)
.group(:id)
child_users_users
is the wonky alias that .left_joins(:child_users)
creates.
At least on Postgres the driver (the PG gem) will automatically cast the result to a an array but YMMV on the other dbs.