如何找到与特定条件无关的记录? (ActiveRecord / PostgreSQL)

时间:2017-02-03 22:36:23

标签: ruby-on-rails ruby postgresql activerecord

我有以下ActiveRecord模型:

class User < ApplicationRecord
    has_many :user_alert_archives
end

class UserAlertArchive < ApplicationRecord
    belongs_to :user
    belongs_to :alert
end

class Alert < ApplicationRecord
    has_many :user_alert_archives
end

当用户归档给定警报时,将使用该用户的ID和警报ID创建UserAlertArchive记录。对用户的归档警报运行查询非常简单。

Alert.joins(:user_alert_archives).where(user_alert_archives: {user_id: current_user.id})

它正在查询我遇到麻烦的那种情况的逆转。如何对具有与当前用户ID相关联的UserAlertArchive的警报记录进行有效查询?

- 编辑 -

这有点难以解释,但这是我能够获得理想结果的唯一方式:

archived_ids = Alert.joins(:user_alert_archives).where(user_alert_archives: {user_id: current_user.id}).pluck(:id)
Alert.where.not(id: archived_ids)

这在技术上有效,但它会提取存档警报的所有ID,这对于拥有数千个警报的用户来说非常慢。如果可能的话,我希望能够在一个查询中完成它。

2 个答案:

答案 0 :(得分:2)

使用Rails 5(方法'jeft_joins'退出)

Alert.left_joins(:user_alert_archives).where(user_alert_archives: {id: nil})

这将显示所有从未被任何人归档的警报。

如果您想要所有未由某个特定用户归档的警报,那么您可能需要添加一些sql:

Alert.where('id NOT IN (SELECT alert_id FROM user_alerts_archives u WHERE u.customer_id = ?)', current_user.id)

如果你有像UserAlert这样的模型,它持有警报状态(如'待定','已存档'),那么查询它们可能会更加美观和流畅。

答案 1 :(得分:0)

我喜欢M. Stavnycha使用子选择的方法,因此您不必将大量id s传递给IN子句。我建议将其放在Alert的范围或类方法中。即。

class Alert < ApplicationRecord
  has_many :alert_archives

  def self.unviewed(user_id)
    where("id NOT IN (SELECT alert_id FROM user_alert_archives WHERE user_id = ?)", user_id)
  end
end