如何用Rails的group和pluck实现按属性分组返回ID数组哈希?
解决Group后获取ID数组哈希的问题
嘿,我明白你的需求——你想把分组后的account_id对应到它所属的所有Model ID数组,但直接用Model.group(:account_id).pluck(:id)报错了对吧?这是因为group和pluck的组合在这里不适用:group(:account_id)会让SQL按account_id分组,但pluck(:id)试图直接取出id字段,这时候数据库不知道怎么返回分组后的ID集合,所以抛出了ActiveRecord::StatementInvalid错误。
下面给你几个可行的解决方案,你可以根据数据量和数据库类型来选:
方案一:内存分组(简单直观,适合小数据量)
用Ruby的group_by先把所有记录按account_id分组,再提取每个分组的ID数组:
Model.all.group_by(&:account_id).transform_values { |records| records.map(&:id) }
这个方法非常容易理解,缺点是会把所有Model记录加载到内存里,如果你的数据量很大,可能会有性能问题。
方案二:数据库原生聚合(性能更好,适合大数据量)
不同数据库有不同的聚合函数来把分组后的ID拼成数组,直接在数据库层面完成计算:
PostgreSQL用户
用array_agg函数直接生成数组:
Model.group(:account_id) .select("account_id, array_agg(id) as ids") .map { |result| [result.account_id, result.ids] } .to_h
MySQL用户
用GROUP_CONCAT把ID拼成字符串,再转成数组:
Model.group(:account_id) .select("account_id, GROUP_CONCAT(id) as ids") .map do |result| [result.account_id, result.ids.split(',').map(&:to_i)] end.to_h
方案三:遍历分组记录构建哈希
如果你不想用group_by加载所有记录,也可以遍历分组后的结果逐步构建哈希:
Model.group(:account_id) .select(:account_id, :id) .each_with_object({}) do |item, hash| hash[item.account_id] ||= [] hash[item.account_id] << item.id end
这个方法会分批加载记录(取决于你的数据库游标设置),内存占用比group_by小一些。
内容的提问来源于stack exchange,提问作者Blair Anderson
相关产品推荐
相关产品推荐

