【问题标题】:Rails, iterate through result of group queryRails,遍历组查询的结果
【发布时间】:2017-01-13 20:42:25
【问题描述】:

如果这已经存在,我深表歉意,我已经看过但找不到这个确切的问题。

假设我有三个 ActiveRecord 模型,Continent、Country 和 Town。 Town 有一个属性 population,我有兴趣通过汇总各个城镇的人口来分解每个国家/地区的人口,按大陆分组。

因为一个国家有很多城镇,而一个大陆的国家相对较少,而且只有几个大陆,我可能会继续做这样的事情:

continents = {}
Continent.each do |continent|
  country_breakdown = {}
  continent.countries.each do |country|
    country_breakdown[country] = country.towns.sum(:population)
  end
  continents[continent] = country_breakdown
end

...然后在视图中遍历continents。

问题在于这具有 SQL 复杂性O(n),其中n 是国家/地区的数量。

我的问题是:有什么方法可以让 SQL 生成(在单个查询中)这个分组结果,然后我们可以像在 Rails 中视图侧的普通嵌套 Hash 一样迭代它?

我尝试过使用 ActiveRecord::QueryMethods#group,但我完全不知道如何迭代由此产生的结果。

【问题讨论】:

    标签: sql ruby-on-rails activerecord


    【解决方案1】:

    是的,有。假设您已经完全描述了您的关系:

    class Continent
      has_many :countries
      has_many :towns, through: :countries
    end
    
    class Country
      belongs_to :continent
    
      has_many :towns
    end
    
    class Town
      belongs_to :country
    
      has_one :continent, through: :country
    end
    

    你应该可以跑了:

    results = Continent.joins(:town).group(:continent_id, :country_id).sum(:population)
    

    这将为您提供[[continent_id, country_id], population] 格式的哈希。

    e.g. {[2, 38]=>39993, [1, 31]=>127425, [5, 12]=>113556, [5, 76]=>2966, [1, 10]=>263473, [1, 34]=>154492, [2, 37]=>55087...}
    

    联接使您可以访问查询中的 Town 模型,Continent 知道这是因为 has_many through: 关系。

    您可以对该哈希进行迭代以获取您想要的格式的数据:

    formatted = results.each_with_object({}) do |((continent_id, country_id), pop), m|
      m[continent_id] ||= {}
      m[continent_id][country_id] = pop
    end
    
    e.g. { continent_id => { country_id => population } }
       {2=>{38=>39993, 37=>55087}, 1=>{31=>127425, 10=>263473...}
    

    可能有更有效的方法来执行此步骤。将每个条目映射到真实对象可能很有用,这样您就不会迷失哪个数字指的是哪个值。但无论如何,这会将您的数据库访问减少到一个查询,这将比原始实现快得多。

    【讨论】:

    • 啊,完美! group 对我不起作用,因为根据您的资格,我们的关联没有正确定义。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2015-12-16
    • 2015-07-19
    • 2021-10-22
    • 1970-01-01
    • 2015-05-09
    • 2016-07-08
    • 2011-06-15
    • 2021-02-15
    相关资源
    最近更新 更多