2017-10-07 10 views
0

Book has_many Reviewsがあり、Bookにクラスメソッドを追加して私のホームページに「最近レビュー」した本を表示しました。私はこれを試してみた:Rails:結合テーブルを注文した後に重複を削除する

def self.recently_reviewed 
    Book.joins(:reviews).order('reviews.created_at DESC').limit(5) 
end 

多くの重複したレコードを生成するので、私はそうのようなdistinctを使用してみました:

Book.joins(:reviews).order('reviews.created_at DESC').distinct.limit(5) 

私も前にそれを試してみましたが、.order後、どの

ActiveRecord::StatementInvalid: PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list 

私はこれを解決する方法についてちょっと混乱していますが、私は.selectに少し柔軟性を持たせるべきですか?

+0

あなたの団体が正しく設定されていれば、最後の 'n'' Reviews'の' Book.title'を見つけてみませんか? – Andy

答えて

1

Book.joins(:reviews).order('reviews.created_at DESC').distinct

では、書籍やレビューの結合表とは別個の予約を選択し、[ reviews.created_at時間に応じて個別の予約のリストを注文しようとしています。 SQLは次のようになります。

SELECT DISTINCT "books"."id" FROM "books" INNE JOIN "reviews" ON "reviews"."book_id" = "books"."id" ORDER BY reviews.created_at 

これは許されない理由があります。結果は不確定であるためです。あなたは1つの本のための100のレビューを持っていると想像してください。参加表には、100の行があり、すべての異なるレビューがあります。別のリストを選択すると、この本の1行が表示されます。これは、結合表の100のいずれかになります。その後、このレビューのcreated_atに基づいてこれを注文します。レビューが100のいずれかになる可能性があるため、注文は毎回異なる可能性があります。

これは完全に罰金のようになります。

Book.joins(:reviews).order('books.id DESC').distinct

、それはその本を選ぶの100行のどの問題ではありませんので、books.idは同じです。

問題に戻ってください。あなたが最近のレビューで5冊の本を手に入れようとしているようです。私はそれを行うための簡単な方法が表示されませんが、ここに私のソリューションです:

res = Review.group("book_id").maximum("created_at") # {book_id => create_at}, each book with its most recent review time 
arr = res.to_a.sort { |a,b| b[1]<=>a[1] } #array sorted by created_at in desc order 
arr.map{ |n| n[0] }.take(5) #top 5 books' ids with most recent reviews 
0

これは、それがサブクエリを必要とするため、それは最も単純な形式だではActiveRecordが処理できる以上の複雑なDBのクエリは実際には。私は完全にクエリでこれを行うだろうかここにあります:

SELECT book.* 
FROM  book 
     INNER JOIN books on reviews.book_id = books.id 
WHERE reviews.created_on = (SELECT MAX(reviews.created_at) 
           FROM reviews 
           WHERE reviews.book_id = books.id) 
GROUP BY books.id 

私は次のことを行うだろうActiveRecordのにこれを変換するには:

class Book 
    scope :recently_reviewed, joins(:reviews) 
    .where('reviews.created_on = (SELECT MAX(books.created_at) FROM reviews WHERE reviews.book_id = books.id)') 
    .group('books.id') 
end 

あなたは、最後のレビューを持っているすべての書籍のリストを取得することができます以下の手順を実行して:

Book.recently_reviewed 

その後、

書籍のn個の数のリストを取得することができます
0

これを試しましたか?

def self.recently_reviewed 
    Review.preload(:book).order(created_at: :desc).limit(5).map(&:book) 
end 
関連する問題