我有一个名为Awardunit
的模型。 Awardunit
有许多Awardleaders
。一个奖项单位可以有一个或多个奖项领导者。
如果我获取所有记录或搜索并获取一个名为awardunits
的变量的记录集合,我如何计算此集合中所有单位中Awardleaders
的数量?
这就是我的所作所为:
@leaders = 0
@awardunits.each do |unit|
@leaders = @leaders + unit.awardleaders.size
end
再次计算残疾领导者,我用这个:
@disabledleaders = 0
@awardunits.each do |unit|
@disabledleaders = @disabledleaders + unit.awardleaders.where(disabled: true).size
end
如果我使用它,每次页面加载时都必须经过所有记录。有没有更好的方法呢?
答案 0 :(得分:8)
您可以通过添加计数器缓存来便宜地计算关联:
class AwardUnit << ActiveRecord::Base
has_many :award_units
end
class AwardLeader << ActiveRecord::Base
belongs_to :award_unit, counter_cache: true
end
现在在新迁移中向award_leaders_count
表添加一个名为AwardUnit
的新列:
def change
add_column :award_units, :award_leaders_count, :integer, default: 0
AwardUnit.all.each do |unit|
AwardUnit.reset_counters(unit.id, :award_leaders)
end
end
Rails现在会自动缓存每个AwardUnit
的award_leaders数量,@my_award_unit.award_leaders.count
将为您提供计数,而无需运行其他数据库查询。
默认情况下,Rails counter_cache
仅适用于所有award_leaders。如果您只需要计算那些有条件的award_leader,您将需要添加自己的counter_cache:
class AwardUnit << ActiveRecord::Base
has_many :award_units
end
class AwardLeader << ActiveRecord::Base
belongs_to :award_unit
scope :disabled, -> { where(disabled: true) }
after_save :update_counter_cache
after_destroy :update_counter_cache
def update_counter_cache
award_unit.update_attribute(:disabled_award_units_count, award_unit.award_leaders.disabled.count)
end
end
迁移:
def change
add_column :award_units, :disabled_award_leaders_count, :integer, default: 0
AwardUnit.all.each do |unit|
unit.update_attribute(:disabled_award_units_count, unit.award_leaders.disabled.count)
end
end
现在,当你有一组AwardUnit
时,获得残疾奖励领导人的总数就像
@award_units = AwardUnit.limit(5).to_a # or a similar query
@award_units.inject(0){|sum,unit| sum + unit.disabled_award_leaders_count }
答案 1 :(得分:2)
您可以在抓取Awardleaders
时急切地加载Awardunit
,这样您就不必为每个Awardunit
执行计数查询,如下所示:
@awardunits = Awardunit.includes(:awardleaders).where('awardleaders.disabled = ?', true) # the rest of the query
或者,您可以直接查询计数:
@leaders = Awardleader.where('awardunit_id IN (?)', @awardunits.map(&:id)).where(:disabled => true).count
答案 2 :(得分:1)
这将只运行一次数据库查询
Awardunit.includes(:awardleaders).map {|award_unit| award_unit.awardleaders.size}.inject(0){|sum,item| sum + item }