我在:users和:books之间有一个has_and_belongs_to_many关系。他们加入了:owned_books模型。我的应用程序的一个功能是连接已阅读相同书籍的用户。目前,我在我的模型中无效地处理了这个问题:
users_hash = Hash.new
users = User.all
users.each do |user|
if user != current_user
users_hash[user.id] = 0
user.books.each do |book|
if current_user.books.include?(book)
users_hash[user.id]+=1
end
end
end
end
users_hash = users_hash.sort {|a,b| b[1]<=>a[1]}
@users = Array.new
users_hash[0..max].each do |id|
user = User.find(id[0])
@users << user
end
end
我相信有一种方法可以让数据库完成这项工作。我一直在玩一个看起来像这样的MySQL查询:
@users = User.select("users.*, COUNT(books) AS shared_books").joins("LEFT JOIN books ON ???").order("shared_books DESC").limit(100)
我的目的是加入current_user已阅读的书籍,然后计算所有其他用户的数量,以查看他们阅读过的书籍数量。然后,我将按此计数订购结果,并限制前100名结果。
不幸的是,我的MySQL技能不能满足要求。特别是,我不确定如何为连接的模型编写条件。我也怀疑select语句是否有效,但是一旦我有一个可靠的连接语句,我可能会想到这一点。
答案 0 :(得分:0)
如果正确构建数据,通常可以在单个操作中获取所需内容。在您的情况下,您可能需要稍微调整一下这个结构:
class User < ActiveRecord::Base
has_many :owned_books
has_many :books,
:through => :owned_books
end
class OwnedBook
belongs_to :user
belongs_to :book
end
class Book
has_many :owned_books,
:as => :owned_by
has_many :users,
:through => :owned_by
end
使用较新的has_many :through
比has_and_belongs_to_many
方法有许多优点,主要是因为实现更新,但也因为使用关联的方式区分了您的连接模型和正在连接的模型。管理关联也更容易,因为每个OwnedBook实际上是一个可以使用id
进行更改,更新或销毁的一流模型。
要在这种情况下使用通用图书获取用户,请尝试以下操作:
User.where('id IN (SELECT DISTINCT user_id FROM owned_books WHERE book_id IN (SELECT book_id FROM owned_books WHERE user_id=?))', @user.id)).all
这有点啰嗦,因为它可以避免重复用户。如果您只是使用通用书籍获取用户,则可能会为每个用户获得多个匹配项。这就是将DISTINCT
条件添加到查询中的原因。