ActiveRecord中的计数关联

问题描述 投票:0回答:3

我有两个模型,UserGroup,其中组包含许多用户。如果我想使用一个查询来统计每个组中的用户数,则可以使用以下SQL:

select id, (select count(1) from users where group_id = groups.id) from groups

使用ActiveRecord是否可以有效地做到这一点?

为清楚起见,此查询将列出所有组ID,以及每个组中的用户数。

ruby activerecord associations aggregate-functions
3个回答
1
投票

    使用关联
  1. group = Group.find(1) #find group with id = 1 group.users.count # count users whose group_id = 1 calls db everytime or group.users.size # get size from cache if group.users loaded
  2. 或直接
  3. User.where(:group_id=>1).count

count助手在指定条件下在数据库上触发一个count(*)查询检查更多选项http://apidock.com/rails/ActiveRecord/Calculations/count

我也建议您通过rails guides

0
投票
Group.all( :select => "groups.id, count(u.group_id) as users_count", :joins => "LEFT OUTER JOIN users u ON u.group_id = groups.id", :group => "groups.id" )

0
投票
subquery = User.where("users.group_id = groups.id").select('count(1)') groups_with_count = Group.select(:id, "(#{subquery.to_sql}) as users_count")

或对相同结果使用sql分组

groups_with_count = Group.joins(:users).select(:id, 'count(users.id) as users_count').group(:id)

在两种情况下,您现在都可以使用MINIMAL原始sql在一个查询中获得结果:

groups_with_count.each { |group| puts "#{group.id} => #{group.users_count}" }

附加说明
您可以使用以下帮助程序将第一个子查询编写为subquery = User.via(:group).select('count(1)'),这是更简单且可维护的imo。

我已经在多个项目中使用此代码,以便编写更好的子查询:

class ApplicationRecord < ActiveRecord::Base # transform Raw sql that references an association such as: Shift.where('shifts.id = checkins.shift_id') # into a simpler version Shift.via(:checkin) if shift have the checkin relationship # No support for polymorphic association # Basic support for "through" reflection (using join) def via(name) association = reflect_on_association(name) raise ArgumentError, "#{name} is not a valid association of #{self.class.name}" unless association raise NotImplementedError if association.polymorphic? join_keys = association.join_keys table_column = arel_table[join_keys.foreign_key] association_column = Arel::Table.new(association.table_name)[join_keys.key] if association.through_reflection? through_association = association.through_reflection table_column = Arel::Table.new(through_association.table_name)[join_keys.foreign_key] joins(through_association.name).where(table_column.eq(association_column)) else where(table_column.eq(association_column)) end end end ```

© www.soinside.com 2019 - 2024. All rights reserved.