【Laravel】EloquentのfirstOrCreate・firstOrNew・updateOrCreate の違いと使い分け

LaravelのEloquentには、「レコードを取得しつつ、なければ作成する」という処理を簡潔に書けるメソッドが複数あります。

firstOrCreateupdateOrCreate の違いがわからない」

firstOrNew はいつ使うの?」

「取得したレコードが新規か既存かを判定したい」

この記事では、3つのメソッドの違いと実務での使い分けを、具体的なコード例とともに解説します。

1. 3つのメソッドの違い(比較表)

メソッドレコードが存在する場合レコードが存在しない場合DBに保存
firstOrCreate既存レコードを返す新規作成して返す✅ する
firstOrNew既存レコードを返す新規インスタンスを返す❌ しない
updateOrCreate既存レコードを更新して返す新規作成して返す✅ する

一言でまとめると:

  • firstOrCreate → 取得するか、なければ作る(更新はしない)
  • firstOrNew → 取得するか、なければインスタンスだけ作る(保存は自分でする)
  • updateOrCreate → 取得して更新するか、なければ作る

2. firstOrCreate の使い方

firstOrCreate は第1引数の条件でレコードを検索し、見つかれば返します。見つからなければ第1引数と第2引数をマージした値で新規レコードを作成して返します。

// 基本的な使い方
$user = User::firstOrCreate(
    ['email' => 'test@example.com'],  // 検索条件
);

// 第2引数で作成時のみ使う値を指定
$user = User::firstOrCreate(
    ['email' => 'test@example.com'],  // 検索条件
    ['name' => 'Test User', 'role' => 'member']  // 作成時のみ使う値
);

wasRecentlyCreated で新規か既存かを判別する

firstOrCreate の戻り値には wasRecentlyCreated プロパティがあり、新規作成されたかどうかを確認できます。

$user = User::firstOrCreate(
    ['email' => 'test@example.com'],
    ['name' => 'Test User']
);

if ($user->wasRecentlyCreated) {
    // 新規作成された場合の処理
    Mail::to($user)->send(new WelcomeMail($user));
} else {
    // 既存レコードが返された場合の処理
    Log::info('既存ユーザーがログインしました', ['id' => $user->id]);
}

実務での使用例

// OAuth認証でユーザーを取得または作成
$user = User::firstOrCreate(
    ['provider' => 'google', 'provider_id' => $googleUser->id],
    [
        'name'  => $googleUser->name,
        'email' => $googleUser->email,
    ]
);

// タグの取得または作成
$tag = Tag::firstOrCreate(['name' => $tagName]);

// 設定値の取得または作成(デフォルト値付き)
$setting = UserSetting::firstOrCreate(
    ['user_id' => $userId, 'key' => 'theme'],
    ['value' => 'light']  // デフォルト値
);

3. firstOrNew の使い方

firstOrNewfirstOrCreate とほぼ同じですが、DBへの保存を行いません。インスタンスを返すだけなので、保存前に追加の処理をしたい場合に使います。

$user = User::firstOrNew(
    ['email' => 'test@example.com'],
    ['name' => 'Test User']
);

// この時点ではDBに保存されていない(新規の場合)
// $user->exists で既存かどうかを確認できる
if (!$user->exists) {
    // 追加の処理
    $user->activation_token = Str::random(32);
    $user->save(); // ここで保存
}

firstOrCreate との使い分け

// firstOrCreate:取得 or 即時作成(追加処理不要な場合)
$tag = Tag::firstOrCreate(['name' => $tagName]);

// firstOrNew:取得 or インスタンス生成(保存前に追加処理が必要な場合)
$profile = UserProfile::firstOrNew(['user_id' => $userId]);
$profile->last_login_at = now();
$profile->save();

実務での使用例

// バリデーション後に保存する場合
$address = Address::firstOrNew(['user_id' => $userId]);
$address->fill($validatedData);

if ($address->isDirty()) {
    $address->save();
    event(new AddressUpdated($address));
}

4. updateOrCreate の使い方

updateOrCreate は第1引数の条件でレコードを検索し、見つかれば第2引数で更新します。見つからなければ第1引数と第2引数をマージして新規作成します。

// 基本的な使い方
$user = User::updateOrCreate(
    ['email' => 'test@example.com'],  // 検索条件
    ['name' => 'Updated Name', 'role' => 'admin']  // 更新または作成する値
);

firstOrCreate との違い

$email = 'test@example.com';

// firstOrCreate:既存レコードは更新しない
$user = User::firstOrCreate(
    ['email' => $email],
    ['name' => 'New Name']
);
// → 既存レコードがあれば name は変わらない

// updateOrCreate:既存レコードも更新する
$user = User::updateOrCreate(
    ['email' => $email],
    ['name' => 'New Name']
);
// → 既存レコードがあれば name が 'New Name' に更新される

実務での使用例

// 外部APIのデータを同期する(upsert的な処理)
foreach ($apiResponse['users'] as $userData) {
    User::updateOrCreate(
        ['external_id' => $userData['id']],
        [
            'name'       => $userData['name'],
            'email'      => $userData['email'],
            'updated_at' => now(),
        ]
    );
}

// ユーザー設定の保存(存在すれば更新、なければ作成)
UserSetting::updateOrCreate(
    ['user_id' => $userId, 'key' => 'notification_enabled'],
    ['value' => $enabled ? '1' : '0']
);

// プロフィールの更新または初期作成
UserProfile::updateOrCreate(
    ['user_id' => auth()->id()],
    $request->validated()
);

5. 実務での使い分け基準

30年のLaravel実務から整理した判断基準です。

既存レコードを更新したくない場合firstOrCreate

例:タグの取得・作成、OAuth認証のユーザー作成

保存前に追加処理が必要な場合firstOrNew

例:トークン生成、複数テーブルへの紐付け処理

常に最新の値で上書きしたい場合updateOrCreate

例:外部APIとのデータ同期、設定値の保存

まとめ

やりたいこと使うメソッド
なければ作る(あっても更新しない)firstOrCreate
なければインスタンス生成(保存は自分で)firstOrNew
あれば更新、なければ作るupdateOrCreate
新規か既存かを判定したいwasRecentlyCreated プロパティ
既存かどうかを確認したい(firstOrNew後)$model->exists プロパティ

迷ったときの判断軸は「既存レコードを更新したいかどうか」です。更新したいなら updateOrCreate、したくないなら firstOrCreate を選べばほぼ間違いありません。