Rails按has_many关联的结果计数排序

ran*_*ika 48 activerecord ruby-on-rails ruby-on-rails-3

无论如何我可以通过子模型()返回的项目数来订购结果(ASC/ )吗?DESCJobs

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

例如:我需要打印最高职位的公司

She*_*yar 85

Rails 5+

引入了对左外连接的支持,Rails 5因此您可以使用外连接而不是使用它counter_cache来执行此操作.这样您仍然可以保留具有0个关系的记录:

Company
  .left_joins(:jobs)
  .group(:id)
  .order('COUNT(jobs.id) DESC')
  .limit(10)
Run Code Online (Sandbox Code Playgroud)

查询的SQL等价物是这个(通过调用.to_sql它得到):

SELECT "companies".* FROM "companies" LEFT OUTER JOIN "jobs" ON "jobs"."company_id" = "companies"."id" GROUP BY "company"."id" ORDER BY COUNT(jobs.id) DESC
Run Code Online (Sandbox Code Playgroud)

  • 这应该是真正有效的答案,如果你删除`.limit(10)`,你可以让公司有0个工作,而其他答案你会错过0个工作公司. (2认同)

Bil*_*han 41

如果您希望经常使用此查询,我建议您使用内置的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
Run Code Online (Sandbox Code Playgroud)

然后像使用它一样

@featured_company = Company.featured
Run Code Online (Sandbox Code Playgroud)

  • 好吧,我真的不想为此添加额外的列. (5认同)
  • 但是你必须在`jobs`表上为每个插入更新`companies.jobs_count`表.那是2个写在2个不同的表上.收益在哪里? (5认同)
  • 非常有帮助,+ 1.AFAICS,只有缺少的东西:如果数据库有数据,你将从count = 0开始,除非你这样做:`Company.find_each {| company | Company.reset_counters(company.id,:jobs)}`. (3认同)
  • 这取决于。没有完美的解决方案。如果性能和干净的代码优先,那么添加一列也没什么坏处。 (2认同)
  • 看起来很乱我:( (2认同)

小智 25

就像是:

Company.joins(:jobs).group("jobs.company_id").order("count(jobs.company_id) desc")
Run Code Online (Sandbox Code Playgroud)

  • 有了这个,如果对象有0个关系,它就会消失. (20认同)

Tan*_*Tan 21

@ user24359正确的应该是:

Company.joins(:jobs).group("companies.id").order("count(companies.id) DESC")
Run Code Online (Sandbox Code Playgroud)


小智 6

添加到 Tan 的答案中。包括 0 个关联

Company.joins("left join jobs on jobs.company_id = companies.id").group("companies.id").order("count(companies.id) DESC")
Run Code Online (Sandbox Code Playgroud)

默认情况下,joins使用内连接。我尝试使用left join包含 0 关联