这是一个图书馆系统,人们可以在这里借书。每本书都属于一个类别。我们想根据他们最常借的书来给人们一些建议。
以下是四种型号:
class Person < AR
has_many :borrows
end
class Borrow < AR
belongs_to :person
belongs_to :book
end
class Category < AR
has_many :books
end
class Book < AR
has_many :borrows
belongs_to :category
end
我写了SQL来找书
SELECT * FROM books WHERE category_id =
(SELECT category_id FROM books WHERE id IN
(SELECT book_id FROM borrows WHERE person_id =10000)
GROUP BY category_id ORDER BY count(*) DESC LIMIT 1)
AND id NOT IN
(SELECT book_id FROM borrows WHERE person_id =10000)
这似乎有效,但我想知道如何用Rails方式编写finder ...
答案 0 :(得分:2)
你可以做以下事情,亲自写下来.rb
has_many :books, :through => :borrows
has_many :categories_of_books, :through => :books, :source => :category
&安培;
def suggested_books
Book.where("category_id IN (?) AND id NOT IN (?)", self.categories_of_books, self.books)
end
虽然它会导致超过1个查询,但它干净,您只需要这样做:
@user.suggested_books
答案 1 :(得分:1)
使用活动记录,您可以删除三个子查询中的两个以支持连接:
Book.where(
category_id: Category.limit(1)
.joins(:books => :borrows)
.where("borrows.person_id = ?", 10000)
.group("categories.id")
.order("COUNT(*) DESC")
.pluck("categories.id")
).joins(:borrows).where("borrows.person_id != ?", 10000)
仍然不是最佳解决方案,因为它会生成两个单独的查询(一个用于Category
上的内部查询)。根据您的需要,这可能不会那么糟糕,例如,如果您决定使用内部查询的结果(相关用户中借用最多的类别)来做其他事情。
答案 2 :(得分:0)
可能是这样的:
@person = Person.find(10000)
@categories = @person.books.map{|b| b.category}.uniq!
@suggestions = @categories.map{|c| c.books} - @person.books
为了让'@ person.books'正常工作,你必须添加你的Person模型:
has_many :books, :through => :borrows