groupメソッドとは?
指定したカラムの各値ごとにグループ化するメソッド。
下記のテーブルから、各ownerのcatの数のデータを抽出してみる。
(catsテーブルからowner_idごとにグループ化し、ownerごとに何匹ネコを飼っているか数え上げる)
irb(main):045:0> Cat.group(:owner_id).count
(0.2ms) SELECT COUNT(*) AS count_all, "cats"."owner_id" AS cats_owner_id FROM "cats" GROUP BY "cats"."owner_id"
=> {1=>2, 2=>1, 3=>1}
この場合、owner_id=1の人(田中さん)が2匹、owner_id=2の人(伊藤さん)が1匹、owner_id=3の人(高橋さん)が1匹
ただこれだと少しわかりにくい。。。(理想は、〇〇さんが何匹飼っているみたいにわかれば良い。)
今度は、各ownerがcatを何匹飼っているのかをownerのnameごとに分けたネコの数のデータ抽出してみる。
結果は、下記の通り。
(catsテーブルとownersテーブルを内部結合したデータを抽出。つまり今回でいうと飼われているcatのみのデータが残る。)
irb(main):052:0> Cat.joins(:owner)
Cat Load (0.3ms) SELECT "cats".* FROM "cats" INNER JOIN "owners" ON "owners"."id" = "cats"."owner_id" /* loading for inspect */ LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Cat id: 1, name: "クロ", owner_id: 2, created_at: "2022-10-01 01:17:50.679955000 +0000", updated_at: "2022-10-01 01:17:50.679955000 +0000">, #<Cat id: 2, name: "モモ", owner_id: 1, created_at: "2022-10-01 01:18:33.127365000 +0000", updated_at: "2022-10-01 01:18:33.127365000 +0000">, #<Cat id: 3, name: "ハナ", owner_id: 3, created_at: "2022-10-01 03:10:26.125535000 +0000", updated_at: "2022-10-01 03:10:26.125535000 +0000">, #<Cat id: 4, name: "ミー", owner_id: 1, created_at: "2022-10-01 01:19:31.494863000 +0000", updated_at: "2022-10-01 01:19:31.494863000 +0000">]>
↓
今回は、catsテーブルのcatは全て飼われているので、catsテーブルは上記の内容のままである。
(次に、内部結合したcatsテーブルをownersのnameごとにグループ化し、そのcatの数を出力しようとし、下記コマンドを実行。)
irb(main):053:0> Cat.joins(:owner).group("owner.name").count
(0.7ms) SELECT COUNT(*) AS count_all, "owner"."name" AS owner_name FROM "cats" INNER JOIN "owners" ON "owners"."id" = "cats"."owner_id" GROUP BY "owner"."name"
Traceback (most recent call last):
1: from (irb):53
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: owner.name)
↓
ただし、エラー発生。ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: owner.name)の内容は、「ActiveRecord::StatementInvalid (SQLite3::SQLException: そのような列はありません: owner.name)」。
つまり、ownerにはnameカラムがないということ。groupメソッド内の引数owner.nameのownerをownersに変更し、そのnameカラムの値ごとにグループ化する。
(*今回の状況で使用したgroupメソッドの引数には、owners.nameのようにテーブル名.カラム名でなければ、グループ化できないらしい。)
(ownersテーブルのnameの値ごとにグループ化し、それぞれのcatの数を数える。)
irb(main):054:0> Cat.joins(:owner).group("owners.name").count
(0.3ms) SELECT COUNT(*) AS count_all, "owners"."name" AS owners_name FROM "cats" INNER JOIN "owners" ON "owners"."id" = "cats"."owner_id" GROUP BY "owners"."name"
=> {"伊藤"=>1, "田中"=>2, "高橋"=>1}
↓
上記内容より、伊藤さんは1匹、田中さんは2匹、高橋さんは1匹といったデータを得ることができた。