组合模型以解决没有范围的n + 1个查询

时间:2014-03-17 17:56:29

标签: ruby-on-rails ruby

我有这些数据的数组:

{user_id: 1, schedule_id: 4, some_more_fields: 'yup'}

这是一些数据处理的结果。正如您所注意到的,这些数据与用户和日程表相关联 - 因此,对于体面的输出,我应该打印用户的名称和日程安排的时间。

由于ActiveModel不支持关系,因此无法使用ActiveModel进行此关联,但可以使用活动记录tabless gem完成此关联。但是,这是对数据库的快速查询:它会触发对每条记录的查询。它是经典的,可以通过includes轻松解决,但includes不幸地只适用于范围(我只有一个Ruby原生数组)。

我可以通过手动映射id到手动查询解决这个问题,并手动粘贴一个到另一个实现一个实体的一个请求,但我发现这种方式非常缺乏吸引力。

这是更可接受的方式吗?

更新

好的,让我们深入了解一下。 用户与Schedule无关。当计划进行(这是一段时间)用户获得一些统计数据(如评级)。然后我需要总结 - 用户获得了多少好票和坏票。在使用一些group SQL语句进行处理之后,我得到类似

的内容
[{user_id: 1, schedule_id: 4, good: 5, bad: 10},
{user_id: 2, schedule_id: 4, good: 80, bad: 0}
{user_id: 3, schedule_id: 4, good: 0, bad: 0}]

然后我试图在我的视图中显示这些数据,如

@tracks.each do |track|
  "#{track.user.name} got #{track.good} and #{track.bad} votes"
end

track.user是通过user_id的关联,每次点击都会加载用户。所以我的SQL输入是

User Load (0.4ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
User Load (0.4ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
User Load (0.4ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 3 LIMIT 1

这很糟糕。 到目前为止我唯一的想法就是将用户缓存在哈希中,比如

# cache
@users = { }
User.where(id: @tracks.map(&:user_id)).each do |user|
  @users[user.id] = user
end

# in view
@tracks.each do |track|
  "#{@users[track.user_id]} got #{track.good} and #{track.bad} votes"
end

但我发现这种方式没有吸引力。我该怎么办?

1 个答案:

答案 0 :(得分:0)

不确定我是否完全理解了这个问题或更多,所以您正在寻找的输出,但您可以尝试这个

User.joins(:schedules).where(id:your_array.collect{|h| h[:user_id]},schedules:{id:your_array.collect{|h| h[:schedule_id]}})

这应该产生:

SELECT users.* FROM users INNER JOIN schedules ON schedules.id = users.schedule_id WHERE users.id IN (...) AND schedules.id IN(...)