Rails Query group and pluck to Return Array of IDs grouped by another attribute?
At least in newer versions of Rails and PostgreSQL this is possible:
pairs = Model.select(:account_id, 'array_agg(id)')
.group(:account_id)
.pluck(:account_id, 'array_agg(id)')
This returns:
[
[1, [535, 536]],
[2, [542, 567, 588]],
]
which can be converted into a hash:
Hash[*pairs.flatten(1)]
{
1 => [535, 536],
2 => [542, 567, 588],
}
array_agg
is a PostgreSQL function, but I assume MySQL's GROUP_CONCAT
would work, too.
I think the question is not relevant anymore but it would help someone who came across similar question.
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
The function GROUP_CONCAT() works for MySQL 5.6. For MySQL 5.7+ you may use JSON_ARRAYAGG().
For PostgreSQL you need to use array_agg() or string_agg()
Hope it will help.
Postgres has an json_agg aggregate function that can be used to get an aggregate of the ids:
psql=# SELECT models.group_id, json_agg(id) AS ids FROM models GROUP BY models.group_id;
group_id | ids
----------+-----------------------------------------------
34 | [149]
43 | [170, 171, 172]
25 | [106, 107]
32 | [134, 135, 136, 137, 138, 139]
8 | [29, 30, 31, 32, 33, 34, 35, 36]
12 | [53]
10 | [39, 40, 41, 42, 43, 44, 45]
26 | [108, 109, 110, 111, 112, 113, 114]
11 | [46, 47, 48, 49, 50, 51, 52]
18 | [70, 71, 72, 73, 74, 75, 76, 77, 78]
16 | [61, 62, 63, 64]
You can use this in a raw SQL query in rails to and use each_with_object
to produce a hash with the group_id's as keys.
class Model < ApplicationRecord
belongs_to :group
def self.by_group
sql = Model.select(:group_id, 'json_agg(id) AS ids')
.group(:group_id)
.to_sql
rows = connection.select_all(sql)
rows.each_with_object({}) do |row, hash|
hash[row["group_id"]] = JSON.parse(row["ids"])
end
end
end
irb(main):001:0> Model.by_group
(1.7ms) SELECT models.group_id, json_agg(id) AS ids FROM models GROUP BY models.group_id;
=> {34=>[149], 43=>[170, 171, 172], 25=>[106, 107], 32=>[134, 135, 136, 137, 138, 139], 8=>[29, 30, 31, 32, 33, 34, 35, 36], 12=>[53], 10=>[39, 40, 41, 42, 43, 44, 45], 26=>[108, 109, 110, 111, 112, 113, 114], 11=>[46, 47, 48, 49, 50, 51, 52], 18=>[70, 71, 72, 73, 74, 75, 76, 77, 78], 16=>[61, 62, 63, 64], 39=>[167], 3=>[3, 4], 47=>[184, 185, 186, 187], 13=>[54, 55, 56, 57], 49=>[193, 194, 195, 196, 197, 198, 199, 200], 22=>[93, 94, 95, 96, 97, 98], 9=>[37, 38], 24=>[104, 105], 14=>[58, 59, 60], 45=>[179], 46=>[180, 181, 182, 183], 48=>[188, 189, 190, 191, 192], 17=>[65, 66, 67, 68, 69], 28=>[115, 116, 117], 36=>[155], 38=>[158, 159, 160, 161, 162, 163, 164, 165, 166], 4=>[5, 6, 7, 8, 9, 10, 11, 12, 13], 30=>[119, 120, 121, 122, 123, 124, 125], 50=>[201, 202], 33=>[140, 141, 142, 143, 144, 145, 146, 147, 148], 6=>[23], 40=>[168], 19=>[79, 80, 81], 29=>[118], 2=>[1, 2], 21=>[85, 86, 87, 88, 89, 90, 91, 92], 23=>[99, 100, 101, 102, 103], 41=>[169], 31=>[126, 127, 128, 129, 130, 131, 132, 133], 35=>[150, 151, 152, 153, 154], 20=>[82, 83, 84], 5=>[14, 15, 16, 17, 18, 19, 20, 21, 22], 44=>[173, 174, 175, 176, 177, 178], 7=>[24, 25, 26, 27, 28], 37=>[156, 157]}