【问题标题】:Using ActiveRecord to search through an object's associations and return instances where all of the associations do/do not contain a certain value使用 ActiveRecord 搜索对象的关联并返回所有关联包含/不包含特定值的实例
【发布时间】:2016-09-12 21:44:41
【问题描述】:

我正在尝试查询对象的关联,并且只返回所有关联都具有特定值的对象。例如,如果一个 User 有一个 memberships 关联,并且 members 有一个 active(boolean) 字段,我想返回一个包含所有只有 active: false 的会员资格的用户。

我现在正在处理的查询是:

User.includes(:memberships).where(memberships: {active: false})

但是,这给了我所有具有非活动成员资格的用户,以及同时拥有 active: falseactive: true 成员资格的所有用户。我尝试对此做一个额外的 .where.not ,但当然,它返回了同一个组。

我考虑过映射用户集合并创建一个新数组,将具有活跃成员资格的用户踢出,但我需要将最终值保留为 AR 集合,因为我继续在控制器中进一步查询它。

我更愿意为此坚持使用 ActiveRecord,但如果它不可行而我需要使用 SQL,我也愿意。

任何帮助将不胜感激。谢谢!

【问题讨论】:

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


    【解决方案1】:

    这里有几件事 - 您需要一个 LEFT OUTTER 连接,因此请确保您的 SQL 查询构造正确。检查与

    User.includes(:memberships).where(memberships: {active: false}).explain
    

    User.includes(:memberships).where(memberships: {active: false}).to_sql
    

    其次,试试:

    User.joins(:memberships).where("memberships.active = ?", false)
    

    或者试试.merge,我喜欢用这个:

    User.joins(:memberships).merge(Membership.inactive)
    

    假设您在 Membership 模型上有一个范围/类方法 .inactive

    def self.inactive
      where(active: false)
    end
    

    .includes 应该仅在您需要将关系加载到内存中时才使用。

    编辑:

    排除具有单个(或多个)成员资格的任何用户的最简单方法是将其拆分为 2 个查询。

    active_user_ids = Membership.active.pluck(:user_id).uniq
    User.where("id NOT IN (?)", active_user_ids.join(","))
    

    【讨论】:

    • 谢谢!我已经确认我正在使用 .explain 使用 Left Outer Joins,并且还尝试了 joins 方法。我遇到了同样的问题。如果用户同时拥有 Active 和 Inactive 成员资格,他们仍会被退回。
    • @swats - 我更新了我的答案。要留在 AR 中,而不是陷入讨厌的 SQL 语句,只需拆分查询。除非您没有数百万用户,否则这仍然非常高效(加入该字符串可能会很昂贵)。
    【解决方案2】:

    排除具有有效和无效会员资格的用户尝试--

    User.includes(:memberships).where(memberships: {active: false}).where.not(memberships: {active: true})

    此外,您可能希望使用#joins 而不是#includes。如果除了查询之外不需要访问成员资格,则无需将其加载到内存中(#include 会这样做)。

    这篇文章有一个很好的解释—— http://tomdallimore.com/blog/includes-vs-joins-in-rails-when-and-where/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-19
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      • 2022-07-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多