【问题标题】:Looking for correct query for where.not.any in Rails ActiveRecord在 Rails ActiveRecord 中寻找 where.not.any 的正确查询
【发布时间】:2018-01-25 21:40:30
【问题描述】:

Rails 初学者问题。
我有一个用户表和一个团队表。

一个用户有很多团队,团队属于用户。

我想查询用户是否没有团队。 我正在使用这个查询:

    User.joins(:teams).where.not(teams: {team_name: 'coconuts'})

除非用户拥有多个团队,否则此方法有效。
例如,用户 Bill 在椰子团队和面包果团队。
上面的查询会返回 Bill,因为他在椰子团队中应该被排除在外。

我明白为什么会发生这种情况,但我想不出另一个适用于这种情况的查询。
获取这些数据的正确方法是什么?
我正在使用 Rails 4。

【问题讨论】:

  • 您是否尝试检查用户的团队大小,例如 @user.teams.length.zero? 如果用户不属于任何团队,则返回 true,这是否解决了问题?
  • 嘿@AmrAdel,不幸的是,这不起作用,因为即使用户在另一个团队中,我也需要知道用户是否不在团队中。不过谢谢:)

标签: mysql ruby-on-rails activerecord


【解决方案1】:

尝试以下,请考虑simple and clean code vs performance

team = Team.find_by(name: 'coconuts')

excluded_user_ids = team.user_ids
User.where.not(id: excluded_user_ids)

# If you want more a little bit efficiently and suppose you have the join model `Membership`
excluded_user_ids = team.memberships.pluck(:user_id)

# Or if you want more efficiently (just 1 query) and suppose you're using Postgresql
User
  .left_outer_joins(:teams)
  .group('users.id')
  .select("users.*, count(teams.id) AS count_foo, count(teams.id) filter (where teams.name = 'coconuts') AS count_bar")
  .having('count_foo != count_bar')

【讨论】:

  • 我没有使用 Postgres,所以我不确定最后的查询,但第一个查询将通过一个小的调整来工作:User.where.not(id: Team.where(team_name: 'coconuts').pluck(:user_id)).pluck(:email, :id) -- find_by 只会返回第一个结果。
  • User.where.not(id: Team.where(team_name: 'coconuts').pluck(:user_id)).pluck(:email, :id) 比接受的答案快一点(基于非常粗略的测试)---谢谢!
  • 如果你想收集而不是第一个结果,你可以这样做:excluded_user_ids = Membership.joins(:team).where('teams.name = ? OR teams.name = ?', 'foo', 'bar').pluck(:user_id)
  • 因为 DBMS 本身有很多算法可以做这样的事情,所以我们应该总是更喜欢 SQL 而不是 Ruby。尝试添加几千条记录以查看不同,Rails 日志可能无济于事,因为它只“记录” SQL 时间
  • 您可以搜索conditional count 并调整select 子句
【解决方案2】:

只使用 Ruby,而不是活动记录,你可以这样做

User.select {|user| user.teams.pluck(:team_name).exclude?('coconuts')
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    相关资源
    最近更新 更多