如何根据多对多关系选择用户子集?

时间:2015-07-31 14:57:29

标签: ruby-on-rails ruby ruby-on-rails-4 associations

UserOrganization通过Relationship建立了多对多关联。

Relationship模型中的一个变量是一个名为member的布尔值 user模型可以多次出现Relationship,因为user可能与多个organizations相关。

如何从所有users中选择1)与任何organization没有关系的随机实例(因此不会出现在Relationship模型中)加上2)与组织有关系但users 所有与组织的关系的那些member = false

我想的是:

user = User.where( relationship_id = nil || ??? ).offset(rand(0..100)).first

5 个答案:

答案 0 :(得分:2)

我会这样做

  1. User.joins("LEFT JOIN relationships ON relationships.user_id = users.id").where('relationships.user_id IS NULL').offset(rand(0..100)).first

  2. 类似的东西:

    member_ids = Relationship.where(member: true).pluck(:user_id).uniq
    users = User.where.not(id: member_ids) # or User.where('id NOT in (?)', member_ids) on Rails < 4 
    

答案 1 :(得分:1)

所以,你真正想要的是那些不是任何组织成员的用户,其中“成为成员”意味着“拥有一个成员=真的关系连接记录”。这比您指定的条件简单得多。

在那种情况下:

  • 从member = true
  • 的关系中获取不同的user_id
  • 获取ID不在此列表中的用户

例如

member_ids = Relationship.where(member: true).distinct.pluck(:user_id)
@users = User.where("id not in (?)", member_ids).all

答案 2 :(得分:0)

获取没有组织的用户:

User.where.not(id: Relationship.pluck(:user_id).uniq)

如果没有一些逻辑可以将用户的总关系与member = false的关系进行比较,那么另一个查询似乎不是你可以做的事情。

答案 3 :(得分:0)

现在可以使用Where Exists宝石了。 (完全披露:我最近创造了这个宝石。)

# This will select all users, for which there are not relationships,
# or there is a relationship, but its 'member' attributes is false.
#
# Just what you've asked for.
users_to_select = User.where_not_exists(:relationships, member: true)

# 'offset' and 'count' will work as usual after 'where_not_exists'
random_user = users_to_select.offset(rand(users_to_select.count)).first

答案 4 :(得分:-1)

好吧,使用ActiveRecord并不认为您被禁止编写SQL代码。实际上,在许多情况下,您必需这样做。您的案例似乎是其中之一(您不能使用ActiveRecord进行'OR'查询,并且SQL'WHERE EXISTS'没有语法糖。)

所以我建议你这样做:

free_users = User.where("NOT EXISTS (SELECT 1 FROM relationships WHERE user_id = users.id) OR NOT EXISTS (SELECT 1 FROM relationships WHERE user_id = users.id AND member = FALSE)")
random_user = User.find(free_users.ids.sample)

有关SQL“EXISTS”的更多信息:

http://www.techonthenet.com/sql/exists.php

<强> UPD 即可。发布了另一个使用where_exists gem的答案。