資料庫遷移是對資料庫所做的修改。這些修改可能包括更改表格的結構、更新一組記錄中的數據、填充數據或刪除一系列記錄。

資料庫遷移通常在應用程序啟動前運行,且對於同一資料庫不會成功運行多於一次。資料庫遷移工具保存了在資料庫中運行的遷移歷史,以便將來跟踪。

在本文中,您將學習如何在一個最小的 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文件,因为配置内容可能包含数据库密码,不应将其暴露给公众。 .env文件通常通过.gitignore文件隐藏,因此更安全。该项目将使用.env文件进行ts-migrate-mongoose配置。

文件应包含以下键及其值:

  • 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 創建一個用戶集合

Mongoose 模式可用於創建用戶集合(或表)。用戶文檔(或記錄)將擁有以下字段(或列):emailfavouriteEmojiyearOfBirth

要為用戶集合創建 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

您可以將代碼更新為下面片段中的代碼:

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 為我們提供了 CLI 命令,用於運行遷移腳本的 updown 函數。

使用 npx migrate up <name-of-script> 可以運行特定腳本的 up 函數。使用 npx migrate up 可以運行數據庫中 statedown./migrations 文件夾中所有腳本的 up 函數。

在應用程序啟動之前運行遷移,我們會使用 npm 腳本。具有前綴pre的 npm 腳本將在沒有pre前綴的腳本之前運行。例如,如果有一個dev腳本和一個predev腳本,每當運行dev腳本時使用npm run devpredev腳本將在運行dev腳本之前自動運行。

我們將使用 npm 腳本的這個功能將 ts-migrate-mongoose 命令放在一個prestart腳本中,以便在start腳本運行之前運行遷移。

更新package.json文件,添加一個運行 ts-migrate-mongoose 命令以運行項目中遷移腳本的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));
};

如果我們啟動應用程序並訪問http://localhost:8000使用Postman或瀏覽器,我們會得到一個類似下面的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"
    }
  ]
}

請注意,如果再次運行應用程序,遷移腳本將不再運行,因為遷移的狀態在成功運行後將為

請查看存儲庫的fetch-users分支,以查看本文中代碼庫的當前狀態。

結論

在構建應用程序時,當需要為測試種子初始數據、種子管理用戶、通過添加或刪除列來更新數據庫模式以及更新多條記錄的列值時,遷移是很有用的。

如果您使用Mongoose和MongoDB,ts-migrate-mongoose可以幫助為您的Node.js應用程序運行遷移提供框架。