2013-06-08 16 views
25

Esiste comunque la possibilità di ordinare i risultati (ASC/DESC) per numero di elementi restituiti dal modello figlio (Jobs)?Ordine di rotaie per numero di risultati di has_many associazione

@featured_companies = Company.joins(:jobs).group(Job.arel_table[:company_id]).order(Job.arel_table[:company_id].count).limit(10) 

Per esempio: ho bisogno di stampare le aziende con la più alta di posti di lavoro in cima

risposta

31

Se prevedete di utilizzare questa query di frequente, vi consiglio di utilizzare built -in counter_cache

# Job Model 
class Job < ActiveRecord::Base 
    belongs_to :company, counter_cache: true 
    # ... 
end 

# add a migration 
add_column :company, :jobs_count, :integer, default: 0 

# Company model 
class Company < ActiveRecord::Base 
    scope :featured, order('jobs_count DESC') 
    # ... 
end 

e quindi utilizzarlo come

@featured_company = Company.featured 
+4

Beh, davvero non voglio aggiungere una colonna extra per questo. – randika

+1

Dipende. Non c'è una soluzione perfetta. Se le prestazioni e il codice pulito hanno la priorità, aggiungere una colonna non fa male a. –

+4

Ma poi devi aggiornare la tabella 'companies.jobs_count' per ogni inserimento sulla tabella' jobs'. Si tratta di 2 scritture su 2 diversi tavoli. Dov'è il guadagno? –

18

Qualcosa di simile:

Company.joins(:jobs).group("jobs.company_id").order("count(jobs.company_id) desc") 
+16

Con questo, se l'oggetto ha relazioni 0, scompare. – kinunt

+0

c'è una gemma left_join che può essere usata. Ma attenzione, i valori nulli appariranno primi o ultimi a seconda della direzione dell'ordine. Puoi metterli sempre alla ricerca di questo http://stackoverflow.com/questions/5826210/rails-order-with-nulls-last/7055259#7055259 – juliangonzalez

16

@ user24359 quello corretto dovrebbe essere:

Company.joins(:jobs).group("companies.id").order("count(companies.id) DESC") 
35

Rails 5+

Sostegno esterno sinistro si unisce è stato introdotto nel Rails 5 in modo da poter utilizzare un outer join invece di utilizzare counter_cache a Fai questo. In questo modo ci si può comunque tenere i record che hanno rapporti 0:

Company 
    .left_joins(:jobs) 
    .group(:id) 
    .order('COUNT(jobs.id) DESC') 
    .limit(10) 

Lo SQL equivalente della query è questo (ottenuto chiamando .to_sql su di esso):

SELECT "companies".* FROM "companies" LEFT OUTER JOIN "jobs" ON "jobs"."company_id" = "companies"."id" GROUP BY "company"."id" ORDER BY COUNT(jobs.id) DESC 
+0

questa dovrebbe essere la risposta davvero funzionante, se si rimuove '.limit (10)', è possibile ottenere le aziende hanno 0 posti di lavoro mentre altre risposte ti mancheranno le aziende 0 posti di lavoro –

+0

I'm ancora usando Rails 4. Puoi mostrarmi l'SQL raw per questo? – ironsand

+1

Risposta aggiornata. – Sheharyar

0
Company.where("condition here...") 
     .left_joins(:jobs) 
     .group(:id) 
     .order('COUNT(jobs.id) DESC') 
     .limit(10) 
Problemi correlati