如何从ActiveRecord生成按名称分组、日期聚合计数的哈希?
按名称和日期聚合ActiveRecord记录生成指定哈希结构
看起来你需要把ActiveRecord中的记录按名称分组,再对每个名称下相同日期的count字段求和,最终生成嵌套的哈希结构。先提个小细节:你给出的预期哈希结构里有重复的:name键,这在Ruby哈希里是不允许的(后一个会覆盖前一个),所以我会给出两种符合Ruby语法的合理结构实现,你可以根据需求调整。
方案一:数据库层面聚合(推荐,大数据量更高效)
优先用ActiveRecord的分组查询在数据库完成求和,同时处理count为nil的情况(用COALESCE把nil转为0),比拉取所有数据到内存处理效率高得多:
# 第一步:数据库层面分组求和,处理nil的count为0 aggregated_data = YourModel.select( :name, :date, 'COALESCE(SUM(count), 0) AS total_count' ).group(:name, :date) # 第二步:转换成「名称符号为键,日期-计数数组为值」的哈希 result_hash = aggregated_data.each_with_object({}) do |record, hash| name_key = record.name.to_sym hash[name_key] ||= [] hash[name_key] << { date: record.date.to_i, # 把字符串日期转为整数,匹配你的预期格式 count: record.total_count.to_i } end # 如果需要转换成包含name和data字段的数组结构(更符合常规业务场景) result_array = result_hash.map do |name, data| { name: name, data: data } end
方案二:内存中处理(适合小数据量)
如果因为某些限制没法用数据库聚合,可以把所有数据拉取到内存后再分组求和:
# 第一步:拉取所有记录,提前把nil的count转为0 records = YourModel.all.map do |record| { name: record.name, date: record.date, count: record.count || 0 # 避免求和时出现nil } end # 第二步:先按名称分组,再对每个名称下的日期分组求和 result_hash = records.group_by { |r| r[:name] }.transform_values do |name_group| name_group.group_by { |item| item[:date] }.map do |date, date_group| { date: date.to_i, count: date_group.sum { |item| item[:count] } } end end # 同样可以转换成数组结构 result_array = result_hash.map { |name, data| { name: name.to_sym, data: data } }
示例输出
用你给出的测试数据,result_array会输出:
[ { name: :a, data: [{ date: 20190702, count: 0 }, { date: 20190703, count: 20 }] }, { name: :b, data: [{ date: 20190702, count: 10 }] }, { name: :c, data: [{ date: 20190702, count: 8 }, { date: 20190703, count: 20 }] } ]
result_hash的输出则是:
{ a: [{ date: 20190702, count: 0 }, { date: 20190703, count: 20 }], b: [{ date: 20190702, count: 10 }], c: [{ date: 20190702, count: 8 }, { date: 20190703, count: 20 }] }
内容的提问来源于stack exchange,提问作者Ganesh Raju
相关产品推荐
相关产品推荐

