瞎扯淡 Order by count on has_many

mr_night · 2016年02月14日 · 最后由 mr_night 回复于 2016年02月15日 · 2795 次阅读

最近在做一些数据排序的需求,以前都没有接触过按照关联关系的计算结果排序,这次正好做到,对 SQL 不熟,查了一些资料,加上自己的测试,整理一翻,留给自己以后参考。

class User < ActiveRecord::Base
  has_many :articles
end

class Article < ActiveRecord::Base
  belongs_to :user
end
如果需要查询所有的用户,并且按照用户的文章数量进行排序。
class User < ActiveRecord::Base
  has_many :articles

  scope :by_articles_count, joins(:articles).group("users.id").order("count(articles.id) DESC")
end
...
User.by_articles_count

但是很快发现了一个问题,就是说如果没有 article 的用户,是不在结果集之中的。想了半天,发现是 jions 的问题,joins 是 inner join 如果要让这些 article 为 0 的用户也在结果集中,需要 left join,includes 正好是干这个事情。

class User < ActiveRecord::Base
  has_many :articles

  scope :by_articles_count, includes(:articles).group("users.id").order("count(articles.id) DESC")
end
...
User.by_articles_count

这样所有的 user 都在结果集中了。当然,这边只是写了最基本的,如何根据需要变化,碰到再研究。

附上一些参考资料:

stackoverflow-order-by-count-on-association stackoverflow-order-by-count-on-association2 有个现成的 gem: left_join

其中的各种加载方法释疑:

Preload, Eagerload, Includes and Joins

有理解不对的地方,希望大家不吝指正~

你这排序需求可以直接用counter_cache更方便

#1 楼 @schwinn 多谢提醒,我之前也看过,不过 counter_cache 是需要增加数据库字段的,让 rails 自动维护这个 count 字段。我这边的方法只是不想动现有结构之下的办法。 PS:最终我也没有使用上面的办法,因为对于大表之间的关联,只能增加字段来搞或者是上层去切分业务,做到单表计算才行。。。呵呵。大表之间的 join 实在可怕

需要 登录 后方可回复, 如果你还没有账号请 注册新账号