我有这些(简化)模型:
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
为真的所有地址以及用户可以通过群组访问的所有地址。
我认为它有以下几点:
Address.where(public: TRUE).joins(:group_member)
我在附近吗?
我使用Rails 4和PostgreSQL作为我的数据库,如果它可以帮助任何人。
答案 0 :(得分:1)
我认为这会奏效:
Address.joins(group_member: :group).where(is_public: true, groups: {user_id: 12345})
让我们打破这一点。
首先,我们正在调用Address
模型,这是我们想要返回的b / c。
.joins(:group_member)
会通过group_members
Address
关系将地址加入has_one :group_member
。
但是,我们实际上希望更进一步,并加入与group
相关联的group_member
,因此我们使用嵌套连接,这就是为什么它看起来像joins(group_member: :group)
我们加入地址 - > group_member,then group_member - >基。
接下来是where子句。我们想要有两个条件:
.where(is_public: true)
。groups: {user_id: 12345}
。将这些结合起来的结果是:
where(is_public: true, groups: {user_id: 12345})
总而言之,上面的代码行应该得到你想要的东西。
答案 1 :(得分: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} )