【问题标题】:Get all records grouped by field from association and sorted by count in group从关联中获取按字段分组并按组中计数排序的所有记录
【发布时间】:2015-08-27 16:07:17
【问题描述】:

我有 3 个模型:PostCommentUser

Post 有很多Comments

Comment 属于User

User 有字段country_code

我想获取按国家/地区代码分组的所有帖子 cmets,并按每个国家/地区的 cmets 数量排序。

这个查询:

post.comments.joins(:user).group("users.country_code").order('count_all desc').count

返回这样的结果:

{"DE"=>67,
"US"=>8,
"RS"=>8,
"IN"=>8,
"ES"=>7,
"BR"=>6,
...
"UA"=>0

}

我需要的是一个类似的结果,其中国家代码是键,但值是 cmets 数组。我不知道如何实现这一点。

【问题讨论】:

    标签: ruby-on-rails ruby rails-activerecord


    【解决方案1】:

    你可以使用Ruby枚举模块自带的group_by

    post.comments.group_by{ |c| c.user.country_code }
    

    如果您还希望按每组中的 cmets 数量对其进行排序,这也是可能的:

    post.comments.group_by{ |c| c.user.country_code }.sort_by{ |k, v| v.length }
    

    我想以相反的方向进行排序,您可以在排序块中将长度乘以 -1

    post.comments.group_by{ |c| c.user.country_code }.sort_by{ |k, v| v.length * -1 }
    

    【讨论】:

    • 如果 cmets 列表很大(想象一个带有 cmets 的病毒式 facebook 帖子),此操作的性能可能会很糟糕,因为 group_by 会从数据库中加载内存中的所有 cmets。应该避免这种情况,并且只能与固定的已知大小集合一起使用,或者至少与已知最大大小的变量一起使用
    【解决方案2】:

    试试这样的:(未经测试):

    post.comments.joins(:users).select("users.country_code, count(1) as count_all").group("users.country_code").order('count_all desc')
    

    【讨论】:

      【解决方案3】:

      我认为如果您使用 group by 分组将在 sql 中返回一个不会包含所有 cmets 的聚合结果。您应该在 ruby​​ 中包含用户然后分组。像这样的:

      post.comments.includes(:users).inject({}){|r, x| r[x.user.country_code].nil? ? r[x.user.country_code] = [x] : r[x.user.country_code] << x;r} 
      

      【讨论】:

      • 如果您使用 ActiveRecord 方法 group 它会按照您的说法聚合结果,但是如果您使用完全不同的 Ruby 方法 group_by 如我的回答所示,那么它不会聚合,并给出想要的结果。不要使用复杂的 inject 块来做 group_by 简单的事情。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      • 2010-12-02
      • 1970-01-01
      • 1970-01-01
      • 2021-11-04
      • 2014-06-23
      • 2018-02-22
      相关资源
      最近更新 更多