0

私はこれらの(単純化された)モデルを持っています:

Address
public (Boolean)
has_one :group_member

Group
has_many :Group_Members
belongs_to :User

Group_Member
belongs_to :group
belongs_to :address

User
has_many :groups

publicが true であるすべてのアドレスと、ユーザーがグループを通じてアクセスできるすべてのアドレスを選択したいと考えています。

私はそれが次のようなものだと思います:

Address.where(public: TRUE).joins(:group_member)

私はどこか近くにいますか?

誰にも役立つ場合は、Rails 4 と PostgreSQL をデータベースとして使用しています。

4

2 に答える 2

1

次のことを試してみてください。単一のクエリではありませんが、大きな結合テーブルを使用した単一のクエリよりも優れていると思います。

public_addresses = Address.where(is_public: true)
# =>  get all public addresses

user_addresses = current_user.groups.includes(:group_members => :address).
                # includes is to eager load records to avoid N+1 queries
                flat_map{|g| g.group_members.map(&:address)}
                # inner block returns array of addresses for each group
                # flat_map converts the array of arrays to single level 
# => get all addresses associated with the user


all_addresses = (public_addresses + user_addresses).uniq
# =>  remove duplicates

クエリを高速化するには、遅いクエリのインデックスを追加します。例えば

   add_index :groups, :user_id
   # this speeds up finding groups for a given user

   add_index :group_members, :group_id
   # this speeds up finding group_members for a given group

   add_index :addresses, :group_member_id
   # this speeds up finding addresses for a given group_member

その他のオプションは、テーブルuser_addressesを使用することですjoin

   user_addresses = Address.joins(group_member: group).where(groups: {user_id: current_user.id} )
于 2013-09-30T22:37:13.833 に答える