【Laravel】Eloquentにてupsert|データが無ければcreateやinsertあればupdateする方法

Laravel使いのみなさん、upsertってどうしてますか?

プライマリキーなどで検索してデータがない場合にはcreate、ある場合にはupdateをする方法を解説します。

Eloquentにてupsert、データが無ければcreateあればupdateする方法

まずは答えから。updateOrCreateメソッドを使います。

Laravel公式から以下を引用してます。

$flight = Flight::updateOrCreate(
    ['departure' => 'Oakland', 'destination' => 'San Diego'],
    ['price' => 99, 'discounted' => 1]
);

第一引数の配列がupdateをするカラムを探す検索条件です。

第2引数の配列がupdateをする値の配列です。

つまり第一引数がSQLのwhere句に、第2引数がSET句に入るわけです。

それでもし、第一引数に合致するレコードが存在しなければ、updateは行われません。

その代わり、第一引数と第2引数をarray_mergeした(合体した)配列の値でinsertします。

実際のコードはこちら。

public function firstOrCreate(array $attributes = [], array $values = [])
{
    if (! is_null($instance = $this->where($attributes)->first())) {
        return $instance;
    }

    return tap($this->newModelInstance(array_merge($attributes, $values)), function ($instance) {
        $instance->save();
    });
}

これがupdateOrCreate メソッドの動きです。

Laravel公式リファレンスはこちら。

https://laravel.com/api/9.x/Illuminate/Database/Eloquent/Builder.html#method_updateOrCreate

https://laravel.com/docs/9.x/eloquent#upserts

 

もし1レコードだけではなく、複数レコードをupsertしたい場合にはupsertメソッドを使います。


Flight::upsert([
    ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
    ['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);

第一引数にはupdateに指定するカラムと値を多重配列で設定します。

第2引数にはまずupdateのためにデータを検索する対象のカラム名を配列で指定します。今回は2つ指定されています(['departure', 'destination']

なので、departure, destinationの2項目がwhere句に入って検索されます。

つまり生のSQLだとこうなります。

... WHERE departure = 'Oakland' AND destination = 'San Diego';

そしてもしデータが存在すれば第三引数の['price']の値をupdateしにいきます。

つまりこのSQLになるわけです。

UPDATE flights SET price=99 WHERE departure = 'Oakland' AND destination = 'San Diego';

そしてもしこのWHERE句で合致するデータが無い場合には次のSQLになります。

INSERT INTO flights(price,departure,destination) VALUES(99,'Oakland','San Diego');

そしてこれが終わったら第一引数の多重配列の2番目の以下のデータで同じことを実行します。

['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]

upsertメソッドの公式リファレンスはこちら。

https://laravel.com/api/9.x/Illuminate/Database/Eloquent/Builder.html#method_upsert

リレーション先のモデルに対してもほぼ同じ使い方ができます