我的Work
模型包含video_id
,user_id
和其他一些简单字段。我需要在页面上显示最后12个作品,但每个用户只需要1个。目前我试图这样做:
def self.latest_works_one_per_user(video_id=nil)
scope = self.includes(:user, :video)
scope = video_id ? scope.where(video_id: video_id) : scope.where.not(video_id: nil)
scope = scope.order(created_at: :desc)
user_ids = works = []
scope.each do |work|
next if user_ids.include? work.user_id
user_ids << work.user_id
works << work
break if works.size == 12
end
works
end
但我确信有一种更优雅,更快捷的方式,特别是当作品数量增加时。
答案 0 :(得分:1)
这是一个适用于任何SQL数据库且只需最小调整的解决方案。是否认为它的优雅与否取决于你对SQL的喜爱程度。
def self.latest_works_one_per_user(video_id=nil)
scope = includes(:user, :video)
scope = video_id ? scope.where(video_id: video_id) : scope.where.not(video_id: nil)
scope.
joins("join (select user_id, max(created_at) created_at
from works group by created at) most_recent
on works.user_id = most_recent.user_id and
works.created_at = most_recent.created_at").
order(created_at: :desc).limit(12)
end
仅当user_id和created_at的组合是唯一的时才有效。如果该组合不是唯一的,那么您将获得超过12行。
可以在MySQL中更简单地完成。 MySQL解决方案在Postgres中不起作用,我不知道在Postgres中有更好的解决方案,虽然我确定有一个。