Open4

gormでのbulk update、いい方法ないか

shigetaichishigetaichi

https://zenn.dev/neinc_tech/articles/a23a9eda0cd3ae#解決法

まず、素晴らしい記事を見つけた。

mysqlで一括更新を行う際、ELTとFIELD関数を使えば、Bulk insertの時と同様に一回のsqlで実行できる。
これこそがbulk updateって感じの書き方。

insert on duplicate keyも、結局検証して追加か更新かを判定しているので、なかったら追加されてしまうという余計な潜在的ギミックを伴う。

純粋に更新だけしたいときに、ワンチャン追加もされるとなると、開発時の脳内メモリが消費される。

これをgormで実現したいが、可能なのか。

shigetaichishigetaichi

https://qiita.com/makosinhori/items/43d53107ac6a0cfc8b33

bulk insertの場合、すでに実装を行なっている人がいた。これを参考にできそう。
ただ、bulk insertはgormがすでに提供しているので、あくまでも参考に使える。

上記の記事的には、
追加したいデータのストラクト配列から「?」の部分に代入するための適切な配列を生成する
方針だった。良いと思う。ELT, FIELD関数の引数部分に代入できる配列を生成すれば実現できそう。

shigetaichishigetaichi

では、gormを動かせる環境を作りたい。

mysqlはローカルに作成してあるものに検証用のデータベースを用意した。

「gorm 使い方」と調べたときに、以下の記事が出てきた。
https://zenn.dev/a_ichi1/articles/4b113d4c46857a

dbに接続する部分など、わざわざ調べて書いてくのはめんどくさすぎるので、この記事のを丸々使った。

「gorm db 接続 書き方」でググるのではなく、「gorm 使い方」で検索すれば、接続情報も書いてくれてる記事に出くわす可能性が高い。

勘が熟成してきたことを実感させる。

とりあえず一括更新ができれば良いので、上記の使い方の記事内のUserのストラクト配列もそのまま参考にしてinserts

shigetaichishigetaichi

reflectを使って、

         userValue := reflect.ValueOf(user)
	userType := reflect.TypeOf(user)
	numField := userValue.NumField()
	for i := 0; i < numField; i++ {
		field := userType.Field(i)
		fieldValue := userValue.Field(i).String()
		fmt.Printf("%s = %s\n", field.Name, fieldValue)
	}

こんな処理を書いた。

fieldValueのところを、names, ages, emails配列のようなstringスライスに振り分ける想定だった。

なんとそれはできなさそうだ。

なぜか。golangのプログラムでは

まず、やりたいことを整理してみる。

  • 渡されたUsersスライスから、各フィールドごとに振り分けた配列が欲しい
  • そのスライスがどのようなフィールドを持っているかに関係ない実装がしたい

copilotに聞いてみるか。