[英]Rails order by results count of has_many association
Is there anyway I can order the results ( ASC
/ DESC
) by number of items returned from the child model ( Jobs
)?无论如何我可以按从子模型(
Jobs
)返回的项目数对结果( ASC
/ DESC
)进行排序?
@featured_companies = Company.joins(:jobs).group(Job.arel_table[:company_id]).order(Job.arel_table[:company_id].count).limit(10)
For example: I need to print the Companies with highest jobs on top例如:我需要在顶部打印职位最高的公司
Support for left outer joins was introduced in Rails 5
so you can use an outer join instead of using counter_cache
to do this. Rails 5
中引入了对左外连接的支持,因此您可以使用外连接而不是使用counter_cache
来执行此操作。 This way you'll still keep the records that have 0 relationships:这样,您仍将保留具有 0 个关系的记录:
Company
.left_joins(:jobs)
.group(:id)
.order('COUNT(jobs.id) DESC')
.limit(10)
The SQL equivalent of the query is this (got by calling .to_sql
on it):查询的 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
If you expect to use this query frequently, I suggest you to use built-in counter_cache如果你希望经常使用这个查询,我建议你使用内置的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
and then use it like然后像这样使用它
@featured_company = Company.featured
就像是:
Company.joins(:jobs).group("jobs.company_id").order("count(jobs.company_id) desc")
@user24359 正确的应该是:
Company.joins(:jobs).group("companies.id").order("count(companies.id) DESC")
Added to Tan's answer.添加到 Tan 的回答中。 To include 0 association
包含 0 个关联
Company.joins("left join jobs on jobs.company_id = companies.id").group("companies.id").order("count(companies.id) DESC")
by default, joins
uses inner join.默认情况下,
joins
使用内部joins
。 I tried to use left join
to include 0 association我尝试使用
left join
来包含 0 个关联
添加到答案中, direct raw SQL
已从 rails 6 中删除,因此您需要将 SQL 包装在Arel
(如果raw SQL
是安全的,则意味着通过安全避免使用用户输入并以此方式避免SQL injection
) .
Arel.sql("count(companies.id) DESC")
Company.where("condition here...")
.left_joins(:jobs)
.group(:id)
.order('COUNT(jobs.id) DESC')
.limit(10)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.