9
2

【GO】Gormを使って子テーブルのデータを取得したい

Last updated at Posted at 2024-01-26

はじめに

GORMを使って親と子テーブルのデータを両方取得するのに苦労したので、備忘録として残しておきます。
GORMは公式ドキュメントが丁寧に書かれているので、そちらも合わせてご覧いただくと良いかと思います。

結論

preloadを使って子テーブルのデータを取得しました。
preloadとは、Eager Loading(イーガーローディング)の一種で、メインのクエリと一緒に関連するデータを予め読み込む機能です。これにより、N+1問題を避けて子テーブルのデータを取得できます。
JOINSELECTを使うことでも子テーブルのデータを取得できたのですが、今回はより簡単に使えるpreloadを採用しました。
以下の構造体を例にPreloadの使い方を簡単に説明します。

// UserがOrderをhas manyで持つ
type User struct {
	Name   string
	Email  string
	Orders []Order
}

// OrderがOrderDetailsをhas manyで持つ
type Order struct {
	UserID       uint
	Total        float64
	State        string
	OrderDetails []OrderDetails
}

type OrderDetails struct {
	ID          uint
	OrderID     uint
	Price       float64
	Quantity    int
}

UserとそのOrdersを取得する

例えば、全てのUserとそれに紐づくOrdersを取得したい場合、以下のように記述します。

var users []User
db.Preload("Orders").Find(&users)

クエリは以下のようになります。

SELECT * FROM `users`;
SELECT * FROM `orders` WHERE `user_id` IN (ユーザーのIDリスト);

Ordersとそれに紐づくOrderDetailsを取得する

さらに、それぞれのOrderに紐づくOrderDetailsも取得したい場合は、以下のように記述します。

db.Preload("Orders.OrderDetails").Find(&users)

クエリは以下のようになります。

SELECT * FROM `users`;
SELECT * FROM `orders` WHERE `user_id` IN (ユーザーのIDリスト);
SELECT * FROM `order_details` WHERE `order_id` IN (注文のIDリスト);

Preloadするデータに条件指定を入れる

仮にOrderテーブルからstateshippedであるレコードのみを取得し、それに紐づくOrderDetailsも同時に取得したい場合は、以下のように記述します。

var users []User
db.Preload("Orders", "state = ?", "shipped").
   Preload("Orders.OrderDetails").Find(&users)

クエリは以下のようになります。

SELECT * FROM `users`;
SELECT * FROM `orders` WHERE `state` = 'shipped' AND `user_id` IN (ユーザーのIDリスト);
SELECT * FROM `order_details` WHERE `order_id` IN (注文のIDリスト);

終わりに

上記のようにpreloadを使うことで、簡単に子テーブルのデータを取得することができました。簡単に使えるのは大きなメリットなのですが、SELCTと併用できずテーブルのすべてのカラムを持ってしまうためデータが重くなるというデメリットもあります。必要とするデータに応じてJOIN``SELECTと柔軟に使い分けるのがいいと思います。
機会があれば、JOIN``SELECTを使ったデータの取得方法についても書いてみます。

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2