データベースマイグレーションは、データベースに加えられる変更です。これらの変更には、テーブルのスキーマの変更、レコードのデータの更新、データのシーディング、または一連のレコードの削除が含まれる場合があります。

データベースマイグレーションは通常、アプリケーションが開始する前に実行され、同じデータベースに対して成功裏に二度実行されることはありません。データベースマイグレーションツールは、データベースで実行されたマイグレーションの履歴を保存し、将来の目的のために追跡できるようにします。

この記事では、最小限のNode.js APIアプリケーションでデータベースマイグレーションを設定して実行する方法を学びます。私たちは、ts-migrate-mongooseとnpmスクリプトを使用して、マイグレーションを作成し、MongoDBデータベースにデータをシードします。ts-migrate-mongooseは、TypeScriptコードとCommonJSコードの両方からマイグレーションスクリプトを実行することをサポートしています。

ts-migrate-mongooseは、mongooseをオブジェクトデータマッパーとして使用するNode.jsプロジェクトのためのマイグレーションフレームワークです。マイグレーションスクリプトを書くためのテンプレートを提供し、スクリプトをプログラム的におよびCLIから実行するための設定も提供します。

目次

プロジェクトのセットアップ方法

データベース移行のためにts-migrate-mongooseを使用するには、以下が必要です:

  1. mongooseが依存関係としてインストールされたNode.jsプロジェクト。

  2. プロジェクトに接続されたMongoDBデータベース。

  3. MongoDB Compass(オプション – データベースの変更を表示するために使用)。

簡単にするために作成されたts-migrate-mongoose-starter-repoからクローンできるスターターリポジトリが用意されています。リポジトリをクローンし、環境変数を入力してnpm startコマンドを実行してアプリケーションを起動します。

http://localhost:8000をブラウザやPostmanなどのAPIクライアントで開くと、サーバーが正常に起動していることを示す「Hello there!」テキストが返されます。

プロジェクトのts-migrate-mongooseの構成方法

プロジェクトのts-migrate-mongooseを構成するには、次のコマンドでts-migrate-mongooseをインストールします:

npm install ts-migrate-mongoose

ts-migrate-mongooseでは、JSONファイル、TypeScriptファイル、.envファイル、またはCLIを使用して構成できます。構成内容にはデータベースのパスワードが含まれる可能性があるため、一般公開することは適切ではありません。通常、.envファイルは.gitignoreファイルで非表示にされるため、より安全に使用できます。このプロジェクトでは、ts-migrate-mongooseの構成に.envファイルを使用します。

ファイルには、次のキーとその値を含める必要があります:

  • MIGRATE_MONGO_URI – MongoデータベースのURI。これはデータベースのURLと同じです。

  • MIGRATE_MONGO_COLLECTION – マイグレーションが保存されるコレクション(またはテーブル)の名前です。デフォルト値はこのプロジェクトで使用されているmigrationsです。ts-migrate-mongooseはマイグレーションをMongoDBに保存します。

  • MIGRATE_MIGRATIONS_PATH – マイグレーションスクリプトを格納および読み取るためのフォルダへのパスです。デフォルト値は./migrationsで、このプロジェクトで使用されています。

ts-migrate-mongooseを使用してユーザーデータをシードする方法

プロジェクトを作成し、Mongoデータベースに正常に接続できました。この段階で、データベースにユーザーデータをシードしたいと思います。以下の手順が必要です:

  1. ユーザーコレクション(またはテーブル)を作成する

  2. データをシードするためのマイグレーションスクリプトを作成するためにts-migrate-mongooseを使用する

  3. アプリケーションの開始前にユーザーデータをデータベースにシードするためにts-migrate-mongooseを実行する

1. Mongooseを使用してusersコレクションを作成します

Mongooseスキーマを使用してユーザーコレクション(またはテーブル)を作成できます。ユーザードキュメント(またはレコード)には次のフィールド(または列)が含まれます:emailfavouriteEmoji、およびyearOfBirth

ユーザーコレクションのためのMongooseスキーマを作成するには、プロジェクトのルートにuser.model.jsファイルを作成し、次のコードスニペットを含めます:

const mongoose = require("mongoose");

const userSchema = new mongoose.Schema(
  {
    email: {
      type: String,
      lowercase: true,
      required: true,
    },
    favouriteEmoji: {
      type: String,
      required: true,
    },
    yearOfBirth: {
      type: Number,
      required: true,
    },
  },
  {
    timestamps: true,
  }
);

module.exports.UserModel = mongoose.model("User", userSchema);

2. ts-migrate-mongooseでマイグレーションスクリプトを作成します

ts-migrate-mongooseは、マイグレーションスクリプトを作成するために使用できるCLIコマンドを提供しています。

プロジェクトのルートフォルダでnpx migrate create <name-of-script>を実行すると、MIGRATE_MIGRATIONS_PATHフォルダ(この場合は./migrations)にスクリプトが作成されます。<name-of-script>は、作成されるマイグレーションスクリプトファイルの名前です。

ユーザーデータをシードするためのマイグレーションスクリプトを作成するには、次を実行します:

npx migrate create seed-users

このコマンドにより、./migrationsフォルダに、形式<timestamp>-seed-users.tsの名前のファイルが作成されます。ファイルには次のコードスニペットの内容が含まれます:

// ここでモデルをインポートします

export async function up (): Promise<void> {
  // マイグレーションを記述します
}

export async function down (): Promise<void> {
  // マイグレーションを記述します
}

up関数はマイグレーションを実行するために使用されます。 down関数は、必要に応じてup関数が実行したことを元に戻すために使用されます。 私たちの場合、データベースにユーザーをシードしようとしています。 up関数には、データベースにユーザーをシードするコードが含まれ、down関数にはup関数で作成されたユーザーを削除するコードが含まれます。

データベースがMongoDB Compassで検査されると、マイグレーションコレクションには次のようなドキュメントが表示されます:

{
  "_id": ObjectId("6744740465519c3bd9c1a7d1"),
  "name": "seed-users",
  "state": "down",
  "createdAt": 2024-11-25T12:56:36.316+00:00,
  "updatedAt": 2024-11-25T12:56:36.316+00:00,
  "__v": 0
}

マイグレーションドキュメントのstateフィールドはdownに設定されています。 正常に実行されると、upに変更されます。

./migrations/<timestamp>-seed-users.ts内のコードを以下のスニペットのものに更新できます:

require("dotenv").config() // 環境変数をロード
const db = require("../db.js")
const { UserModel } = require("../user.model.js");

const seedUsers = [
  { email: "[email protected]", favouriteEmoji: "🏃", yearOfBirth: 1997 },
  { email: "[email protected]", favouriteEmoji: "🍏", yearOfBirth: 1998 },
];

export async function up (): Promise<void> {
  await db.connect(process.env.MONGO_URI)
  await UserModel.create(seedUsers);}

export async function down (): Promise<void> {
  await db.connect(process.env.MONGO_URI)
  await UserModel.delete({
    email: {
      $in: seedUsers.map((u) => u.email),
    },
  });
}

3. アプリケーションの開始前にマイグレーションを実行

ts-migrate-mongooseは、マイグレーションスクリプトのupおよびdown関数を実行するためのCLIコマンドを提供してくれます。

npx migrate up <name-of-script>で特定のスクリプトのup関数を実行できます。 npx migrate upで、データベースのstatedownのすべてのスクリプトのup関数を./migrationsフォルダー内で実行できます。

アプリケーションの開始前にマイグレーションを実行するには、npmスクリプトを利用します。 pre 接頭辞を持つnpmスクリプトは、pre 接頭辞のないスクリプトよりも前に実行されます。 たとえば、dev スクリプトと predev スクリプトがある場合、dev スクリプトが npm run dev で実行されると、dev スクリプトが実行される前に predev スクリプトが自動的に実行されます。

このnpmスクリプトの機能を利用して、マイグレーションが start スクリプトの前に実行されるように、prestart スクリプトに ts-migrate-mongoose コマンドを配置します。

package.json ファイルを更新し、プロジェクト内のマイグレーションスクリプトの up 関数を実行するための prestart スクリプトを追加します。

  "scripts": {
    "prestart": "npx migrate up",
    "start": "node index.js"
  },

このセットアップでは、アプリケーションを起動するために npm run start を実行すると、prestart スクリプトが実行され、ts-migrate-mongoose を使用してマイグレーションを実行し、データベースにシードを追加します。

npm run start を実行した後、以下のスニペットのようなものが表示されるはずです:

Synchronizing database with file system migrations...
MongoDB connection successful
up: 1732543529744-seed-users.ts 
All migrations finished successfully

> [email protected] start
> node index.js

MongoDB connection successful                      
Server listening on port 8000

この記事のこの時点でのコードベースの現在の状態を確認するには、リポジトリの seed-users ブランチをチェックしてください。

シードデータをフェッチするAPIエンドポイントを構築する方法

データベース内のシードユーザーデータを取得するためのAPIエンドポイントを構築できます。 server.js ファイルで、以下のスニペットのコードに更新します:

const { UserModel } = require("./user.model.js")

module.exports = async function (req, res) {
  const users = await UserModel.find({}) // データベース内のすべてのユーザーを取得

  res.writeHead(200, { "Content-Type": "application/json" });
  return res.end(JSON.stringify({ // 取得したユーザーデータのJSON表現を返す
    users: users.map((u) => ({
      email: u.email,
      favouriteEmoji: u.favouriteEmoji,
      yearOfBirth: u.yearOfBirth,
      createdAt: u.createdAt
    }))
  }, null, 2));
};

アプリケーションを起動し、Postmanやブラウザを使用してhttp://localhost:8000を訪れると、以下のようなJSON応答を受け取ります:

{
  "users": [
    {
      "email": "[email protected]",
      "favouriteEmoji": "🏃",
      "yearOfBirth": 1997,
      "createdAt": "2024-11-25T14:18:55.416Z"
    },
    {
      "email": "[email protected]",
      "favouriteEmoji": "🍏",
      "yearOfBirth": 1998,
      "createdAt": "2024-11-25T14:18:55.416Z"
    }
  ]
}

アプリケーションを再度実行すると、移行スクリプトはもはや実行されません。なぜなら、移行のstateは実行が成功した後にupになるからです。

この記事のこの時点でのコードベースの現在の状態を確認するには、リポジトリのfetch-usersブランチをチェックしてください。

結論

アプリケーションを構築する際に、テスト用の初期データをシードしたり、管理者ユーザーをシードしたり、列を追加または削除してデータベーススキーマを更新したり、複数のレコードの列の値を一度に更新する必要がある場合、マイグレーションは役立ちます。

ts-migrate-mongooseは、MongooseとMongoDBを使用している場合に、Node.jsアプリケーション用のマイグレーションを実行するためのフレームワークを提供するのに役立ちます。