急切加载一个关联但只有一个列
Eager-load an association but ONLY a single column
我有一个这样的自我参照协会:
class User
belongs_to :parent_user, class_name: "User"
has_many :child_users, class_name: "User", foreign_key: :parent_user_id
end
当我获得用户列表时,我希望能够预先加载 child_users
关联,但我只需要其中的 id
列。我需要能够在不引起 n+1 个查询的情况下做这样的事情,并且 最好 而不必加载此模型中的所有其他数据:
users = User.preload(:child_users)
users.map(&:child_user_ids)
上面的工作是将查询限制为两个查询而不是 n+1,但是我将很多完整的对象加载到内存中,当我只关心 id
时我宁愿避免这种情况自己在那些儿童协会上。
您不需要用于加载模型的预加载。您想要 select 一个聚合。这不是 ActiveRecord 查询接口处理的内容,因此您需要使用 SQL 字符串或 Arel 并为您的数据库使用正确的函数。
例如:
# 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
是 .left_joins(:child_users)
创建的奇怪别名。
至少在 Postgres 上,驱动程序(PG gem)会自动将结果转换为数组,但在其他数据库上为 YMMV。
我有一个这样的自我参照协会:
class User
belongs_to :parent_user, class_name: "User"
has_many :child_users, class_name: "User", foreign_key: :parent_user_id
end
当我获得用户列表时,我希望能够预先加载 child_users
关联,但我只需要其中的 id
列。我需要能够在不引起 n+1 个查询的情况下做这样的事情,并且 最好 而不必加载此模型中的所有其他数据:
users = User.preload(:child_users)
users.map(&:child_user_ids)
上面的工作是将查询限制为两个查询而不是 n+1,但是我将很多完整的对象加载到内存中,当我只关心 id
时我宁愿避免这种情况自己在那些儿童协会上。
您不需要用于加载模型的预加载。您想要 select 一个聚合。这不是 ActiveRecord 查询接口处理的内容,因此您需要使用 SQL 字符串或 Arel 并为您的数据库使用正确的函数。
例如:
# 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
是 .left_joins(:child_users)
创建的奇怪别名。
至少在 Postgres 上,驱动程序(PG gem)会自动将结果转换为数组,但在其他数据库上为 YMMV。