"Rails Way" 急于加载具有多个聚合的多个关联是什么?
What is the "Rails Way" to eager loading mutliple associations with multiple aggregations?
我有一个简单的 rails 申请与这些模型竞争:User、Team 和 旅行。关联是:team has_many users
和 user has_many trips
。行程有一个 distance_miles
字段。
我正在开发一个简单的视图来显示 table 个团队及其具有多个聚合的统计数据。
我最初的方法如下,但结果是 N+1 个查询。
@teams.each do |team|
@team.user.joins(:trips).count()
@team.user.joins(:trips).sum(:distance_miles)
end
以下有效,但看起来很难看,因为我最终想添加分页、排序和过滤。
@teams = Team.left_joins(users: :trips)
.select('teams.id, teams.name, SUM(trips.distance_miles) as num_miles, COUNT(trips.id) as num_trips')
.group(:id)
我一直在阅读 preload 和 includes,但似乎无法让它也获得多个聚合。以下内容让我走到了那里,但它现在缺少团队中的字段并且仍然需要其他聚合:
@teams = Team.includes(users: :trips).group(:id).sum('trips.distance_miles')
是否有我缺少的“rails 方式”?
提供 .sum
、.count
的 ActiveRecord::Calculations 只有在非常简单的情况下才真正有用,因为它总是创建一个单独的数据库查询。
您在 .select
的正确轨道上,但可以通过将代码提取到模型中来清理它:
class Team
def self.with_trips
trips = Trip.arel_table
self.left_joins(users: :trips)
.select(
self.arel.projections, # adds the existing select clause
trips[:distance_miles].sum.as(:num_miles),
trips[:id].count.as(:distance_miles)
)
.group(:id)
end
end
使用 .eager_load
而不是 .left_joins
将导致在 Postgres 上出现 PG::GroupingError,因为结果不明确。相反,您需要使用 window function.
我有一个简单的 rails 申请与这些模型竞争:User、Team 和 旅行。关联是:team has_many users
和 user has_many trips
。行程有一个 distance_miles
字段。
我正在开发一个简单的视图来显示 table 个团队及其具有多个聚合的统计数据。
我最初的方法如下,但结果是 N+1 个查询。
@teams.each do |team|
@team.user.joins(:trips).count()
@team.user.joins(:trips).sum(:distance_miles)
end
以下有效,但看起来很难看,因为我最终想添加分页、排序和过滤。
@teams = Team.left_joins(users: :trips)
.select('teams.id, teams.name, SUM(trips.distance_miles) as num_miles, COUNT(trips.id) as num_trips')
.group(:id)
我一直在阅读 preload 和 includes,但似乎无法让它也获得多个聚合。以下内容让我走到了那里,但它现在缺少团队中的字段并且仍然需要其他聚合:
@teams = Team.includes(users: :trips).group(:id).sum('trips.distance_miles')
是否有我缺少的“rails 方式”?
提供 .sum
、.count
的 ActiveRecord::Calculations 只有在非常简单的情况下才真正有用,因为它总是创建一个单独的数据库查询。
您在 .select
的正确轨道上,但可以通过将代码提取到模型中来清理它:
class Team
def self.with_trips
trips = Trip.arel_table
self.left_joins(users: :trips)
.select(
self.arel.projections, # adds the existing select clause
trips[:distance_miles].sum.as(:num_miles),
trips[:id].count.as(:distance_miles)
)
.group(:id)
end
end
使用 .eager_load
而不是 .left_joins
将导致在 Postgres 上出现 PG::GroupingError,因为结果不明确。相反,您需要使用 window function.