私が持っている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
しかし、特に作品の数が増えると、もっとエレガントで速い方法があると確信しています。
これは、最小限の調整で任意の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でより良いソリューションがあるかどうかはわかりませんが、確かにあります。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加