急切加载一个关联但只有一个列

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。