株式会社学びと成長しくみデザイン研究所の藤澤です。
前提
データベースに蓄積されたログから、特定の項目ごとの最新のデータを取得したいことがあるかと思います。
例えば、各タスクの実行状況を記録する TaskLog テーブルがあるとします。このテーブルには、タスクの識別コード(タスクコード)、ステータス、作成日時、更新日時が記録されています。
TaskLog(id, task_code, status, created_at, updated_at)
そして、テーブルには以下のようなデータが存在するとします。
id | task_code | status | created_at | updated_at |
1 | "taskA" | "ok" | 2022/04/01 12:30:00 | 2022/04/01 12:30:00 |
2 | "taskB" | "ok" | 2022/04/02 12:30:00 | 2022/04/02 12:30:00 |
3 | "taskA" | "ng" | 2022/04/03 12:30:00 | 2022/04/03 12:30:00 |
4 | "taskC" | "ng" | 2022/04/04 12:30:00 | 2022/04/04 12:30:00 |
5 | "taskC" | "ok" | 2022/04/05 12:30:00 | 2022/04/05 12:30:00 |
課題と解決法
このデータの中から、タスクコードごとに最新のステータスを取得したいケースを考えます。
その場合、以下のようなコードで取得することが可能です。
TaskLog.order(:created_at).index_by(&:task_code).transform_values(&:status)
#=> {"taskA"=>"ng", "taskB"=>"ok", "taskC"=>"ok"}
このコードでは、
-
.order(:created_at)
で、作成日時順にソート -
.index_by(&:task_code)
で、タスクコードごとにハッシュを作成
という手順を踏んでいます。
index_by
の仕様により、同じキーに紐づく値はあとから取得したもので上書きされます。そして、事前にレコードの作成日時順でソートしていることで、最終的に最新のものがハッシュの値として適用されます。
つまりここでは、各タスクコードごとに作成日時が最新のレコードを取得するということを行っています。
最後に、.transform_values(&:status)
によって必要な値だけ抽出して完了です。