首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何根据has_one关联的属性对模型进行分组和计数?

如何根据has_one关联的属性对模型进行分组和计数?
EN

Stack Overflow用户
提问于 2017-03-24 16:53:43
回答 1查看 1.7K关注 0票数 2

我有一个站模型,可以有多个设备,而每个设备belongs_to一个站。每个站点都有一个地址,这是一个多态模型:

/app/model/station.rb.app

代码语言:javascript
复制
class Station < ApplicationRecord
  has_one :address, as: :addressable, dependent: :destroy
  has_many :devices
end

/app/model/device.rb

代码语言:javascript
复制
class Device < ApplicationRecord
  belongs_to :station
  has_one :address, through: :station
end

/app/model/address.rb

代码语言:javascript
复制
# @attr [String] city City name of address
class Address < ApplicationRecord
  belongs_to :addressable, polymorphic: true
end

现在我需要两组图表数据:

  • 按城市分列的站数
  • 按城市分列的设备数量

真正可行的是按城市计算车站的数量:

代码语言:javascript
复制
def stations_by_city
  # collect data
  tmp_result = Address.where(addressable_type: 'Station').group(:city).count
  # sort and return top five cities
  result = Hash[tmp_result.sort_by { |_k, v| -v }[0..4]]
  # result = {"City-1"=>17, "City-2"=>14, "City-3"=>14, "City-4"=>12, "City-5=>11} 
end

按城市对设备进行同样的操作并不像预期的那样有效。现在我是这样做的:

代码语言:javascript
复制
def devices_by_city
  stations = Station.all.includes(:address)
  tmp_result = {}
  # for each unique city
  list_of_cities.uniq.each do |city|
   number_of_devices = 0
   # check all stations
   stations.each do |station|         
     address = station.address
     # check if station is in city
     if address.city == city
       # and add to counter
       number_of_devices += station.devices.count
     end
    end
    # append to resulting hash
    tmp_result[city] = number_of_devices
  end
  result = Hash[tmp_result.sort_by { |_k, v| -v }[0..4]]
end

def list_of_cities
  cities = []
  stations = Station.all.includes(:address)
  stations.each do |station|
    address = station.address
    cities << address.city
  end
    cities
  end
end

我有重复的数据库查找,它通常是相当丑陋的。如何以更好的方式编写此查询?尝试了各种.joins、.where、..group组合,但它们都不起作用。添加through: :station到设备模型在其他地方有帮助,但并没有简化我的问题.

从应答更新

代码语言:javascript
复制
# start join from station model
tmp_result = Station.joins(:address, :devices).group(:city).count

# start join from device model
tmp_result = Device.joins(station: :address).group(:city).count

从设备模型开始连接是最快的:

代码语言:javascript
复制
Timing for old query
  0.530000   0.050000   0.580000 (  0.668664)
Timing for query starting from station model
  0.020000   0.000000   0.020000 (  0.024881)
Timing for query starting from device model
  0.010000   0.000000   0.010000 (  0.009616)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-24 20:37:44

您可以在joinsStationAddressDevice模型之间创建一个group_by,然后将结果应用于城市,然后应用count

代码语言:javascript
复制
def devices_by_city_updated
  temp_result = Station.joins(:address, :devices).group(:city).count
  result = Hash[tmp_result.sort_by { |_k, v| -v }[0..4]]
end

此查询将执行单个数据库查找以获取所有信息。

您也可以从Device模型开始连接。但是,您必须加入嵌套关联才能工作:

代码语言:javascript
复制
def self.devices_by_city_another
  tmp_result = Device.joins(station: :address).group(:city).count
  result = Hash[tmp_result.sort_by { |_k, v| -v }[0..4]]
end

您可以在医生们中查看更多信息。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43005071

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档