0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PrismaのskipDuplicatesでseedデータを冪等に投入する

Posted at

はじめに

Prismaでseedデータを投入する際、何も考えずにcreateManyを実行すると以下のような状況になることがあります。

  • uniqueキーがあればエラーになる
  • uniqueキーがなければ実行のたびにレコードが増え続ける

これを回避するには、deleteManyで既存データを消してから投入する方法もありますが、既存データを保持したい場合には使えません。

そこで便利なのがskipDuplicatesオプションです。uniqueキーの重複時にエラーを出さずスキップしてくれるため、冪等(べきとう)なseed処理を実現できます。

await prisma.user.createMany({
  data: [
    { email: "alice@example.com", name: "Alice" },
    { email: "bob@example.com", name: "Bob" },
  ],
  skipDuplicates: true,
});

skipDuplicates vs deleteMany

筆者は前者のskipDuplicatesを使った冪等なseed処理を書くことが多いです。
後者はprisma migrate reset -fを実行すると同等の処理ができるため、使い分けをしています。

各データベースでのskipDuplicatesの挙動

ON CONFLICT DO NOTHINGはPostgreSQLでしかサポートされていないと見かけた気がしたので、skipDuplicatesは内部でどのようなSQLを発行しているのか気になったので各DBで確認しました。

PostgreSQL

INSERT INTO "public"."User" ("email","name")
VALUES ($1,$2), ($3,$4), ($5,$6)
ON CONFLICT DO NOTHING

PostgreSQLはON CONFLICT DO NOTHINGを使用しています。

MySQL / MariaDB

INSERT IGNORE INTO `prisma`.`User` (`email`,`name`)
VALUES (?,?), (?,?), (?,?)

MySQLとMariaDBはINSERT IGNOREを使用していました。

注意点: unique制約が必須

skipDuplicatesuniqueフィールドまたはIDフィールドでのみ重複判定が行われます

Do not insert records with unique fields or ID fields that already exist.
Prisma Client Reference

model User {
  id    Int    @id @default(autoincrement())
  email String @unique  // ← これが必要
  name  String?
}

unique制約がないフィールドで重複を避けたい場合、skipDuplicatesでは対応できません。その場合はupsertや事前の存在チェックが必要になります。

サポート状況

Database createMany skipDuplicates 内部実装
PostgreSQL ON CONFLICT DO NOTHING
MySQL INSERT IGNORE
MariaDB INSERT IGNORE
SQLite -
MongoDB -
SQL Server -

Prismaのドキュメントには以下のように記載されています:

Do not insert records with unique fields or ID fields that already exist. Only supported by databases that support ON CONFLICT DO NOTHING. This excludes MongoDB and SQLServer.
Prisma Client Reference

まとめ

  • seedデータにはskipDuplicates: trueを積極的に活用しよう
  • PostgreSQL/MySQL/MariaDBでは問題なく動作する
  • SQLite/MongoDB/SQL ServerではskipDuplicatesは使えない

検証環境

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?