🦾

【Prisma】upsertで冗長なコードとおさらば!レコードの存在チェック不要の便利な更新方法

に公開

はじめに

Prismaを使っていて、こんなコードを書いていませんか?

// 従来の冗長な書き方
const existingUser = await prisma.user.findUnique({
  where: { email: 'example@example.com' },
});

if (existingUser) {
  // 存在すれば更新
  await prisma.user.update({
    where: { email: 'example@example.com' },
    data: { name: '山田太郎' },
  });
} else {
  // 存在しなければ新規作成
  await prisma.user.create({
    data: {
      email: 'example@example.com',
      name: '山田太郎',
    },
  });
}

私は上記の様にコードを書いていました。

しかし、実はこの処理は1行で書けます。それがupsertです!

upsertとは

upsert = update + insert の造語で、データが存在すれば更新、存在しなければ作成する操作を1つのメソッドで実現できます。

メリット

  • ✅ コードがシンプルになる
  • ✅ 存在チェックのクエリが不要

基本的な使い方

構文

await prisma.モデル名.upsert({
  where: {
    // ユニーク制約のあるフィールドで検索
  },
  update: {
    // 存在する場合の更新内容
  },
  create: {
    // 存在しない場合の作成内容
  },
});

シンプルな例

// ユーザープロフィールの更新または作成
const user = await prisma.user.upsert({
  where: {
    email: 'example@example.com',
  },
  update: {
    name: '山田太郎',
    profile: '更新されたプロフィール',
  },
  create: {
    email: 'example@example.com',
    name: '山田太郎',
    profile: '新規プロフィール',
  },
});

console.log(user); // 更新または作成されたユーザー情報

なんとたったこれだけです

実装例

従来の書き方と、今回ご紹介したupsertを利用した書き方で比較してみます。

例1: ユーザー設定の保存

ユーザーの設定を保存する際、初回は新規作成、2回目以降は更新したい場合:

// 従来の書き方(冗長)
const setting = await prisma.userSetting.findUnique({
  where: { userId: user.id },
});

if (setting) {
  await prisma.userSetting.update({
    where: { userId: user.id },
    data: { theme: 'dark', language: 'ja' },
  });
} else {
  await prisma.userSetting.create({
    data: {
      userId: user.id,
      theme: 'dark',
      language: 'ja',
    },
  });
}
// upsertを使った書き方(シンプル)
await prisma.userSetting.upsert({
  where: { userId: user.id },
  update: {
    theme: 'dark',
    language: 'ja',
  },
  create: {
    userId: user.id,
    theme: 'dark',
    language: 'ja',
  },
});

例2: いいね機能

投稿へのいいね(トグル機能)を実装する場合:

// いいねを追加または削除
const like = await prisma.postLike.findUnique({
  where: {
    userId_postId: {
      userId: user.id,
      postId: post.id,
    },
  },
});

if (like) {
  // すでにいいね済みなら削除
  await prisma.postLike.delete({
    where: {
      userId_postId: {
        userId: user.id,
        postId: post.id,
      },
    },
  });
} else {
  // いいねしていなければ追加
  await prisma.postLike.create({
    data: {
      userId: user.id,
      postId: post.id,
    },
  });
}


// upsertでシンプルに(isActiveフラグで管理)
await prisma.postLike.upsert({
  where: {
    userId_postId: {
      userId: user.id,
      postId: post.id,
    },
  },
  update: {
    isActive: !like.isActive, // トグル
  },
  create: {
    userId: user.id,
    postId: post.id,
    isActive: true,
  },
});

注意点

whereにはユニーク制約が必須

upsertwhere句には、@uniqueまたは@@unique@idが設定されたフィールドが必要です。

まとめ

  • upsertを使えば、存在チェック→条件分岐→更新/作成の冗長なコードが不要に
  • パフォーマンスも向上し、コードも読みやすくなる
  • ユニーク制約のあるフィールドでのみ使用可能
  • 設定の保存、関連の更新、トグル機能など、様々な場面で活用できる

今まで冗長に書いていたコードを、ぜひupsertでリファクタリングしてみてください!

参考

Discussion