2017-02-03 32 views
0

我有以下的ActiveRecord型號:如何查找與給定條件無關的記錄? (ActiveRecord的/ PostgreSQL的)

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 

當用戶歸檔指定警報,一個UserAlertArchive一條記錄被與該用戶的ID和警報ID創建。爲用戶的歸檔警報運行查詢是相當簡單的。

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

它正在查詢與那種情況相反的情況,我在麻煩纏身時遇到了麻煩。如何對不要的UserAlertArchive與當前用戶的ID相關聯的警報記錄進行高效查詢?

- 編輯 -

這是一個有點難以解釋,但這是我已經能夠得到想要的結果的唯一途徑:

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,對於有成千上萬個用戶的用戶而言,這些警報相當緩慢。如果可能的話,我希望能夠在單個查詢中完成它。

+1

我不認爲你需要加入才能得到你想要的東西。如果你將這些調用結合起來,它只會運行一個查詢。 Alert.where.not(id:current_user.user_alert_archives.select(:id)) –

+0

好吧,現在我覺得很荒謬。這確實是一個毫無意義的加入。在我們的產品代碼中發現警報稍微複雜一點,我放棄了大腦放屁,然後在這裏發佈。但感謝您指出ActiveRecord會自動將它結合到子查詢中。我沒有意識到它足夠聰明,可以自己做一個「不在」。 – Haronious

回答

2

隨着導軌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的模型,這是持有警報狀態(如「掛起」,「存檔」),然後查詢它們可能會更美觀和平滑。

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 
相關問題