2013-03-23 19 views
6

Let'say, abbiamo "Argomento - Relazione - Categoria".Come trovare i record che mancano i record associati in has_many attraverso l'associazione con Active Record?

Cioè, l'argomento ha_molte categorie attraverso la relazione.

penso che è molto facile da ottenere gli argomenti che con una categoria

#Relationship Model 
    Topic_id: integer 
    Category_id: integer 

    @topics=Topic.joins(:relationships) 

Ma, non ogni argomento ha una categoria. Quindi, come recuperiamo l'argomento che non ha una categoria? C'è una domanda meno?

Forse sembra @topics=Topic.where('id NOT IN (?)', Relationship.all) Lo trovo in activerecord equivalent to SQL 'minus' ma non sono sicuro di questa soluzione.

+1

si fa a non avere la lista da qualcosa come 'Topic.where (:? Categories.nil)' –

+0

AR restituisce un array vuoto quando non si trova in un rapporto non nullo. – holaSenor

+0

@ tester123, esorto per il chiarimento, sto usando Datamapper per un po '. –

risposta

10

Sarebbe meglio come una relazione, davvero. Pensate questo dovrebbe funzionare:

@topics = Topic.joins('left join relationships on relationships.topic_id = topics.id').where('relationships.category_id is null') 

O questo:

@topics = Topic 
    .joins('left join relationships on relationships.topic_id = topics.id join categories on categories.id = relationships.category_id') 
    .group('topics.id').having('count(categories.id) = 0') 
+0

bingo, la risposta corretta è usare un join sinistro –

0

Prova questo, seleziona solo l'argomento in cui le categorie oggetto di relazione ha una lunghezza pari a zero.

@topics = Topic.all.select {|t| t.categories.length == 0 } 
+0

La risposta Mr.Walrus è probabilmente migliore, a seconda di quanti argomenti ci sono nella tua tabella ora e crescita prevista potrebbe non avere importanza, se questo sta solo facendo alcuni controlli ad hoc, ma se questo è chiamato spesso dovresti confrontare tutte e 3 le opzioni e scegliere quella che usa il database nel modo più efficiente. – holaSenor

+2

Questa è una pessima soluzione. Verrà messo in memoria tutti gli argomenti e interrogherà il database separatamente per ognuno di essi. Questo può essere fatto come una singola query, a la soluzione di MrTheWalrus. Nella maggior parte dei casi, qualsiasi logica che possa essere implementata nel database dovrebbe essere implementata nel database. È molto più veloce e molto più efficiente in termini di memoria e CPU. – eirikir

+1

Ouch. Sì, immagina se avessimo un milione di argomenti !, vorrei andare con il suggerimento di @MrTheWalrus. – holaSenor

0

Cercavo la risposta più semplice, che credo è quello di utilizzare includes.

topics = Topic.includes(:relationships).where(relationships: {id: nil})

Un altro modo, che è più corretto e ti fa pensare SQL è LEFT OUTER JOINS.

Topic.joins("LEFT OUTER JOINS relationships ON relationships.topic_id = topics.id") 
    .where(relationships: {id: nil}) 
Problemi correlati