メインコンテンツにスキップ

Expand-and-Contract パターンを使用したデータ移行

10 分

はじめに

本番環境でデータベーススキーマを変更する際、データの一貫性を確保し、ダウンタイムを回避することが重要です。このガイドでは、Expand-and-Contract パターンを使用して、カラム間でデータを安全に移行する方法を紹介します。既存のデータを保持しながら、boolean フィールドを enum フィールドに置き換える実践的な例を順を追って説明します。

前提条件

このガイドを開始する前に、以下が揃っていることを確認してください。

  • Node.js がインストールされていること (バージョン 18 以上)
  • 既存のスキーマを持つ Prisma ORM プロジェクト
  • サポートされているデータベース (PostgreSQL、MySQL、SQLite、SQL Server など)
  • 開発データベースと本番データベースの両方へのアクセス
  • Git ブランチングの基本的な理解
  • TypeScript の基本的な知識

1. 環境のセットアップ

1.1. 初期スキーマの確認

Post モデルを含む基本的なスキーマから始めます

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
}

1.2. 開発ブランチの作成

変更用の新しいブランチを作成します

git checkout -b create-status-field

2. スキーマの拡張

2.1. 新しいカラムの追加

スキーマを更新して、新しい Status enum とフィールドを追加します

model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean? @default(false)
status Status @default(Unknown)
}

enum Status {
Unknown
Draft
InProgress
InReview
Published
}

2.2. マイグレーションの作成

マイグレーションを生成します

npx prisma migrate dev --name add-status-column

3. データの移行

3.1. マイグレーションスクリプトの作成

データ移行用の新しい TypeScript ファイルを作成します

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
await prisma.$transaction(async (tx) => {
const posts = await tx.post.findMany()
for (const post of posts) {
await tx.post.update({
where: { id: post.id },
data: {
status: post.published ? 'Published' : 'Unknown',
},
})
}
})
}

main()
.catch(async (e) => {
console.error(e)
process.exit(1)
})
.finally(async () => await prisma.$disconnect())

3.2. マイグレーションスクリプトのセットアップ

package.json にマイグレーションスクリプトを追加します

{
"scripts": {
"data-migration:add-status-column": "tsx ./prisma/migrations/<migration-timestamp>/data-migration.ts"
}
}

3.3. マイグレーションの実行

  1. DATABASE_URL を本番データベースを指すように更新します
  2. マイグレーションスクリプトを実行します
npm run data-migration:add-status-column

4. スキーマの縮小

4.1. クリーンアップブランチの作成

古いカラムを削除するための新しいブランチを作成します

git checkout -b drop-published-column

4.2. 古いカラムの削除

スキーマを更新して、published フィールドを削除します

model Post {
id Int @id @default(autoincrement())
title String
content String?
status Status @default(Unknown)
}

enum Status {
Draft
InProgress
InReview
Published
}

4.3. クリーンアップマイグレーションの生成

最後のマイグレーションを作成して実行します

npx prisma migrate dev --name drop-published-column

5. 本番環境へのデプロイ

5.1. デプロイのセットアップ

CI/CD パイプラインに次のコマンドを追加します

npx prisma migrate deploy

5.2. デプロイの監視

ログのエラーを監視し、デプロイ後のアプリケーションの動作を監視します。

トラブルシューティング

よくある問題と解決策

  1. デフォルト値の欠落によるマイグレーションの失敗

    • 適切なデフォルト値を追加したことを確認してください
    • 既存のすべてのレコードを移行できることを確認してください
  2. データ損失の防止

    • マイグレーションを実行する前に、必ずデータベースをバックアップしてください
    • 最初に本番データのコピーでマイグレーションをテストしてください
  3. トランザクションのロールバック

    • データ移行が失敗した場合、トランザクションは自動的にロールバックされます
    • エラーを修正して、マイグレーションを再試行してください

次のステップ

最初の Expand-and-Contract マイグレーションが完了したので、以下を実行できます。

詳細情報


Prisma とのつながりを維持する

Prisma の旅を続けるには、以下とつながってください。 アクティブなコミュニティ。最新情報を入手し、参加し、他の開発者と協力しましょう。

皆様のご参加を心から歓迎し、コミュニティの一員としてお迎えできることを楽しみにしています!