業務で、foreach文の中で毎回saveを呼んで処理が重くなってしまっていた部分があり、調べてみるとupsertメソッドを使用すると良いと知ったため、備忘録として残します。
upsertメソッドについて
1つのクエリで、複数のレコードのUpsertを行うことができます。
Upsertとは..
更新対象のデータがすでに存在していればupdateを行い、存在していなければinsertを行う。
今回の業務では、1つのクエリで更新対象のデータを更新したかったため、updateとして利用しました。
使用方法について
例として、Usersテーブルにupsertするケースを挙げます。
また、すでに以下のデータがUsersテーブルに存在するとします。
id | name | |
---|---|---|
1 | yamada | yamada@test.com |
2 | satou | satou@test.com |
$users = [
// update
['id' => 1, 'name' => 'yamada', 'email' => 'yamada2@test.com'],
// update
['id' => 2, 'name' => 'satou', 'email' => 'satou2@test.com'],
// insert
['id' => 3, 'name' => 'tanaka', 'email' => 'tanaka@test.com']
];
User::upsert($users, ['id'],['email']);
id = 1,2はすでに存在しているためupdateされ、id = 3は存在していないためinsertされます。
引数で渡している値については、
- 第1引数
- upsertの対象となるデータの値を配列で渡します。
- 第2引数
- レコードのユニークを識別するカラムの配列を渡します。
(※注意点として、プライマリーキーかユニークキーを選択してください。それ以外だと動きません。) - 第3引数
- updateする際に更新したいカラムの配列を渡します。こちらは省略可能であり、省略すると全カラムが更新されます。
タイムスタンプについて
モデルのタイムスタンプが設定されている場合、第3引数に「created_at」「updated_at」を含めなくても、insert時は「created_at」「updated_at」に値が自動で入り、update時は「updated_at」が自動で更新されます。
実務で実際にupsertメソッドを使用したときの例
foreach文の中で毎回saveメソッドを呼んでいた部分を、以下のようにupsertメソッドで置き換えを行いました。
$upsertUsers = [];
foreach($TargetUsers as $user){
$upsertUsers[] = [
'id' => $user->id,
'send_mail_count' => 1,
];
}
User::upsert($upsertUsers, ['id'],['send_mail_count']);
upsertメソッドはすごく便利のため、皆様もぜひ使ってみてください。
参考記事