2017-11-21 4 views
1

でテーブルを結合しますはを通じて兄弟を見つけることは、私は次の構造を持つモデルのユーザー、グループ、およびメンバーシップを持っているRailsの

class User < ApplicationRecord 
    has_many :memberships 
    has_many :groups, through: :memberships 
end 

class Group < ApplicationRecord 
    has_many :memberships 
    has_many :users, through: :memberships 
end 

class Membership < ApplicationRecord 
    belongs_to :user 
    belongs_to :group 
end 

基本的には、メンバーシップは、ユーザおよびグループのテーブルを結合しています。

ユーザーuserが与えられていると、少なくとも同じグループに属しているすべての兄弟ユーザーを見つけることができますか?それは私が単一のクエリにし、専らアクティブレコードでそれをやってみたい

user.groups.users # assuming such a line were possible 

のようなものですが、それは速いですかはるかに読みやすい場合、私は2つのクエリでOKです。 (それは同様に役立ちます場合はDB言語はPSQLである。)

答えて

1

結合するいくつかの方法が正確に一つのDBクエリを取得するために参加し、サブ選択し、してみてくださいがありますこの1つ:

User 
    .joins(:memberships) 
    .where.not(id: user.id) 
    .where(
    memberships: { 
     group_id: user.memberships.select(:group_id)}) 

PSすべての* _id列の索引を忘れて、高速照会を取得しないでください。
P.P.S.もう1つの方法:2つのサブ選択、1つのDBクエリ。提案のための

user_groups_rel = user 
    .memberships 
    .select(:group_id) 
groups_users_rel = Membership 
    .select(:user_id) 
    .where(group_id: user_groups_rel) 
User 
    .where.not(id: user.id) 
    .where(id: groups_users_rel) 
+0

ありがとうございます!私はちょうどコメントを残すことになっていないと知っているが、これは素晴らしい作品であり、IDをサブセレクトすることは賢明である。 (そして、はい、私はインデックスを持っています:)) –

+0

ああ、1つのコメント:これは重複を防ぐために最後に 'distinct'を使うことができることを認識しました。 –

+0

はい、結果は関係なので、望む通りにチェーンすることができます。また、 'join 'の代わりに' include'を試すこともできます。 'distinct'は必要ありませんが、追加のメモリはARオブジェクトのインスタンス化に費やされます。ちょうどもう一つの変形を追加しました。 –

-1

includesを使用して以下のことを試してみてください。

groups = User.groups.includes(:users) 
groups.each do |group| 
    puts "user = #{group.user}" 
end 
+0

おかげで、これはAR関係を返さない、と単純な配列が使用可能であったとしても、この答えは '利用者の操作を実行して改善しなければならないであろう。一つは、より良いあなたの要件に合ったテスト。 groups.includes(:users).map(&:users).flatten.uniq' –

関連する問題