1

:users と :books の間に has_and_belongs_to_many 関係があります。それらは :owned_books モデルによって結合されています。私のアプリの機能の 1 つは、同じ本を読んだユーザーを接続することです。現時点では、モデルでこれを非効率的に処理しています。

  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 ステートメントが機能するかどうかも疑問ですが、確かな joins ステートメントがあれば、おそらくそれを理解できるでしょう。

4

1 に答える 1

0

データを正しく構造化すれば、通常は 1 回の操作で必要なものを取得できます。あなたの場合、この構造に合わせて少し調整する必要があるかもしれません:

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これが、条件がクエリに追加される理由です。

于 2012-10-22T14:30:28.973 に答える