在Rails中获取最后的相关记录

时间:2013-07-06 09:52:55

标签: ruby-on-rails postgresql activerecord

我一直在寻找最好的方法,这段时间用平庸的结果做到这一点,所以我决定在这里问。

场景如下:我有三个模型,Task,User和Comment,基本上是这样的:

class Task < ActiveRecord::Base
  belongs_to :user
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :task
end

class User < ActiveRecord::Base
  has_many :tasks
  has_many :comments
end

我正在尝试输出一个任务列表(让我们说这个问题的最后10个),以及每个任务的相关最后评论,以及可能的查询次数最少。

谢谢

更新:我结合了Blue Smith和harigopal的解决方案,所以解决方案如下:

class Task < ActiveRecord::Base
  belongs_to :user
  has_many :comments
  has_one :last_comment, -> { order 'created_at' }, class_name: "Comment"
end

然后获取这样的评论:

tasks = Task.joins(last_comment: :user)
  .includes(last_comment: :user)
  .order('tasks.created_at DESC').limit(10).load

产生只有一个查询,这正是我想要的!谢谢!

3 个答案:

答案 0 :(得分:2)

您必须加入这些表,然后急切加载数据以最大限度地减少查询次数。

例如:

tasks = Task.joins(comments: :user)
  .includes(comments: :user)
  .order('tasks.created_at DESC')
  .limit(10).load

comments = tasks.first.comments   # No query, eager-loaded
user = comments.first.user        # No query, eager-loaded

这应该会将查询数量减少到只有一个(非常复杂的一个),因此您必须确保您的索引符合要求! :-D

关于组合联接和包含的官方文档很模糊,但应该有所帮助:http://guides.rubyonrails.org/active_record_querying.html#joining-multiple-associations

修改

这是一个演示应用程序,其模型与您使用上述方法执行eager-loading相同。它使用两个查询来加载数据。启动应用程序以查看其运行情况。

https://github.com/harigopal/activerecord-join-eager-loading

答案 1 :(得分:1)

您可以尝试以下方式:

class Task
  scope :recent, order('created_at desc')
  scope :last, lambda{|n| limit: n }
end

现在您拥有可重复使用的范围:

Task.recent.last(10)

我猜你想输出给定用户的最后10个任务(假设当前登录的用户)。

current_user.tasks.recent.last(10).includes(comments: user)

答案 2 :(得分:1)

你可以试试这个:

class Task < ActiveRecord::Base
  belongs_to :user
  has_many :comments
  has_one :last_comment, :class_name => 'Comment', :order => 'comments.created_at DESC'
end

@tasks = Task.limit(10).includes(:last_comment => :user)

last_comment是一个“虚拟”关联,只加载一条Comment条记录。这种方法的优点是它将使用更少的内存(因为只加载一个Comment和一个相关的User)。如果使用includes(comments: user),它可能会消耗大量内存(如果有很多注释:)。