Rails 查询组并选择返回按另一个属性分组的 ID 数组?

Bla*_*son 10 activerecord ruby-on-rails

我知道这Model.group(:account_id).count将返回 account_ids => counts 的哈希值。

{3=>3, 4=>3, 8=>8, 10=>5, 20=>4}
Run Code Online (Sandbox Code Playgroud)

我想返回一个哈希值 account_ids => ids

{
  3=>[4594, 4599, 4595], 
  8=>[4600, 4603, 4604, 4606, 4609, 4613, 4611, 4605], 
  20=>[4621, 4623, 4624, 4620], 
  10=>[4626, 4627, 4630, 4631, 4628], 
  4=>[222, 1189, 715]
}
Run Code Online (Sandbox Code Playgroud)

我梦想着这样Model.group(:account_id).pluck(:id)做,但它抛出了一个错误:

ActiveRecord::StatementInvalid: PG::GroupingError: ERROR:  column 
"models.id" must appear in the GROUP BY clause or be used in an 
aggregate function
LINE 1: SELECT "models"."id" FROM "models...
Run Code Online (Sandbox Code Playgroud)

我的实际解决方案相当丑陋。似乎应该有更简单的方法

Model.pluck(:id, :account_id).to_h
  .group_by{|k,v| v}
  .transform_values {|v| v.map(&:first) }
Run Code Online (Sandbox Code Playgroud)

Dan*_*ski 6

至少在较新版本的 Rails 和 PostgreSQL 中,这是可能的:

pairs = Model.select(:account_id, 'array_agg(id)')
             .group(:account_id)
             .pluck(:account_id, 'array_agg(id)')
Run Code Online (Sandbox Code Playgroud)

这将返回:

[
  [1, [535, 536]],
  [2, [542, 567, 588]],
]
Run Code Online (Sandbox Code Playgroud)

可以转换为哈希:

Hash[*pairs.flatten(1)]
Run Code Online (Sandbox Code Playgroud)
{
  1 => [535, 536],
  2 => [542, 567, 588],
}
Run Code Online (Sandbox Code Playgroud)

array_agg是 PostgreSQL 函数,但我认为 MySQLGROUP_CONCAT也可以。


Yur*_*ich 5

我认为这个问题不再相关,但它会对遇到类似问题的人有所帮助。

query = "SELECT account_id, GROUP_CONCAT(id) FROM model_name GROUP BY account_id"
Model.connection.execute(query).to_h

=> {1=>"31", 22=>"12,11,10", 78=>"36,35,34,37,1,3,2,38"} # example result
Run Code Online (Sandbox Code Playgroud)

函数GROUP_CONCAT()适用于 MySQL 5.6。对于 MySQL 5.7+,您可以使用JSON_ARRAYAGG()
对于 PostgreSQL,您需要使用array_agg()string_agg()

希望它会有所帮助。

  • 为什么它不再相关了?Rails 5 可以处理这个问题吗? (3认同)