我有一个Bookhas_many Reviews,并且我添加了一个类方法来Book在我的主页上显示“最近审查过的”书籍。我试过这个:
def self.recently_reviewed
Book.joins(:reviews).order('reviews.created_at DESC').limit(5)
end
Run Code Online (Sandbox Code Playgroud)
这会产生许多重复的记录,因此我尝试使用distinct如下:
Book.joins(:reviews).order('reviews.created_at DESC').distinct.limit(5)
Run Code Online (Sandbox Code Playgroud)
我之前和之后也试过.order,其中
ActiveRecord::StatementInvalid: PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
Run Code Online (Sandbox Code Playgroud)
我对如何解决这个问题感到有些困惑,我应该降级.select以获得更大的灵活性吗?
在
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
Run Code Online (Sandbox Code Playgroud)
不允许这样做是有充分理由的。因为结果是不确定的。假设您对一本书有 100 条评论。在连接表中,您将拥有这本书的 100 行,其中包含所有不同的评论。当您选择一个不同的列表时,您最终会得到这本书的一行。这可以是连接表中的 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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1986 次 |
| 最近记录: |