【Rails】Rubyのgroup_byとRailsのgroup
いまいちよく違いがわからずに使っていたgroup_byとgroupについて調べたのでまとめます。
group_byとgroupの違い
- group_byはRuby、groupはRails
- group_byは配列などの繰り返し処理が可能なクラス(Enumerble)のメソッド
- groupはActiveRecord::Relationのメソッド
group_by
group_by
はRubyのEnumerableクラスのメソッドです。
Enumerableクラスは配列などの繰り返し処理が可能なクラスにインクルードされており、
対象のany?やselectなどのデータの存在確認や絞り込みなどを行えるメソッドがあります。
group_byメソッドは渡されたブロック内の処理の実行結果を、
キーと値(配列)のハッシュとして返します。
以下は1 ~ 10の数値を任意の数で割った時の余りをキーとし、
その余りになる数値を値の配列としています。
(1..10).group_by {|i| i % 2}
=> {1=>[1, 3, 5, 7, 9], 0=>[2, 4, 6, 8, 10]}
(1..10).group_by {|i| i % 3}
=> {1=>[1, 4, 7, 10], 2=>[2, 5, 8], 0=>[3, 6, 9]}
この特徴を使えば、特定のカラムで絞り込んだレコードを取得することができます。
Railsのgroupメソッドの場合はレコードの取得に一手間かかります。
「グループ分けした中にそれぞれにレコードがいくつあったか?」という様な使い方をするため、
レコードのデータ自体を取得するにはさらにwhereなどで絞り込む必要があります。
しかしgroup_byメソッドはグループ分けされたレコード自体をより単純に取得することができます。
User.all.group_by(&:age)
=> {"10"=>[<#User:0x000....>,<#User...>],"20"=>[<#User:...>...]}
ただしこちらはあくまでも配列などの繰り返し処理が可能なオブジェクトに対するものであり、
データベースに特化したものではありません。
group
group
はRailsのActiveRecordのメソッドで、MySQLなどのGROUP BYはこちらに当たります。
groupメソッドは通常単体では使用せず、count
などの集計メソッドと併用することで使用できます。
イメージとしてはgroupメソッドでまとめて、countでその合計値を求めるという様な感じです。
以下の例では年齢層でグループ分けして、各グループでレコードがいくつあるかを集計しています。
User.group(:age_group).count
=> {10=>50,20=>160,30=>130}
この特徴を活用すると特に集計処理でとても役に立ちます。
以下のように商品テーブルと、売れた分を記録する商品ステータステーブルがあるとします。
items | |
---|---|
name | 商品名 |
price | 販売価格 |
sale_informations | |
---|---|
item_id | itemのid |
total_sales | 販売数 |
total_price | 販売合計額 |
Item別で総販売数を出したい場合は、group
でグループ化した後で、
sum
を使って合計値を出すことができます。
SaleInformation.group(:item_id).sum(:total_sales)
=>{
1=>104,
2=>152,
3=>68,
...
}
groupメソッドは単体で使用することはなく、count
やsum
の様に集計系のメソッドと併用して使用します。
以下はusersテーブルをageカラムでgroupした場合に発行されるSQLです。
User.group(:age)
=>
SELECT "users"."age", COUNT(*) AS count_all FROM "users" GROUP BY "users"."age";
この場合実際に使用可能なデータとして取得できるレコードは、グループごとに1件だけになります。
各グループ内のレコードすべての情報を一つずつ使用したい場合には工夫が必要になります。
(個人的にその様な場合はRuybの group_by を使用する方が手っ取り早い気がしています…)
まとめ
いかがでしたでしょうか?名前が似ているため混同しやすい二つのメソッドですが、それぞれ全く別物で使用目的も異なっています。今回記事を書くに当たってこちらの記事で勉強させていただきました。どちらもより詳しい解説が書かれています。
roup_by
group
Discussion