按照关联对象的数量计算列表中对象的总数

时间:2016-04-22 15:55:06

标签: sql ruby-on-rails

我有两个型号

class User
 has_many :subscriptions
end

class Subscription
 belongs_to :user
end

我的一个页面我想显示按每个用户订阅数量排序的所有用户的列表。我不喜欢sql查询,但我认为

list = Users.all.joins(:subscriptions).group("user.id").order("count(subscriptions.id) DESC")
这份工作很重要。现在我的问题是,当我尝试使用list计算list.count中的对象总数时,我得到一个带user.id的哈希和订阅计数,就像这样

{11 => 5,
8 => 7,
1 => 11,
...}

如果我的列表按用户名(在用户表中)排序,则list .. .count中的用户总数不会正常工作。我真的想使用.count,因为它在一个宝石中的分页模块中,但任何想法都很棒!

谢谢!

2 个答案:

答案 0 :(得分:0)

我们可以使用单个查询来完成此操作:

User.joins("LEFT OUTER JOIN ( SELECT user_id, COUNT(*) as num_subscriptions
                              FROM subscriptions
                              GROUP BY user_id
                            ) AS temp
                            ON temp.user_id = users.id")
    .order("temp.num_subscriptions DESC")

基本上,我的想法是尝试查询子查询中每个user_id的订阅数,然后加入User。我使用了LEFT OUTER JOIN,因为会有几个users没有任何subscriptions

改进选项:您可以在User内定义范围,以后的使用会更美观:

<强> user.rb

class User < ActiveRecord::Base
 has_many :subscriptions

 scope :sorted_by_num_subscriptions, -> {
   joins("LEFT OUTER JOIN ( SELECT user_id, COUNT(*) as num_subscriptions
                                  FROM subscriptions
                                  GROUP BY user_id
                                ) AS temp
                                ON temp.user_id = users.id")
   .order("temp.num_subscriptions DESC")
 }
end

然后使用它:

User.sorted_by_num_subscriptions

答案 1 :(得分:0)

group时,count方法改变了它的行为,实际上,它返回每个组的计数哈希值,而不是返回记录的总数。 (有关详细信息,请参阅docs)。因此,您使用list.count获得的只是每个用户的订阅计数的哈希值。

因此,您的查询是正确的,您只需要总结各组中的个别计数。这可以通过以下方式完成:

total_count = list.count.values.sum

如果分页调用仅仅调用问题的count,则分页代码通常能够接受具有总计数的参数。例如,will_paginate接受total_entries参数,因此您应该能够将总计数传递给它:

list.paginate(page: 2, total_entries: list.count.values.sum)