L'esecuzione di un join interno alla tabella has_many combinata con un group
o uniq
è potenzialmente molto inefficiente e in SQL sarebbe meglio implementata come semi join che utilizza EXISTS
con una sottoquery correlata.
Ciò consente all'ottimizzatore di query di sondare la tabella dei posti vacanti per verificare l'esistenza di una riga con il project_id corretto. Non importa se c'è una riga o un milione che hanno quel project_id.
Non è così semplice in Rails, ma può essere ottenuto con:
Project.where(Vacancies.where("vacancies.project_id = projects.id").exists)
Allo stesso modo, trova tutti i progetti che non hanno posti vacanti:
Project.where.not(Vacancies.where("vacancies.project_id = projects.id").exists)
Modifica: nelle versioni recenti di Rails viene visualizzato un avviso di deprecazione che ti dice di non fare affidamento exists
sull'essere delegato ad arel. Risolvi il problema con:
Project.where.not(Vacancies.where("vacancies.project_id = projects.id").arel.exists)
Modifica: se ti senti a disagio con l'SQL grezzo, prova:
Project.where.not(Vacancies.where(Vacancy.arel_table[:project_id].eq(Project.arel_table[:id])).arel.exists)
Puoi renderlo meno disordinato aggiungendo metodi di classe per nascondere l'uso di arel_table
, ad esempio:
class Project
def self.id_column
arel_table[:id]
end
end
... così ...
Project.where.not(
Vacancies.where(
Vacancy.project_id_column.eq(Project.id_column)
).arel.exists
)