数据库迁移是对数据库进行的修改。这些修改可能包括更改表的模式、更新一组记录中的数据、播种数据或删除一系列记录。
数据库迁移通常在应用程序启动之前运行,对于同一个数据库,数据库迁移通常只能成功运行一次。数据库迁移工具会保存已在数据库中运行的迁移历史,以便将来可以跟踪。
在本文中,您将学习如何在一个简单的 Node.js API 应用程序中设置和运行数据库迁移。我们将使用 ts-migrate-mongoose 和一个 npm 脚本来创建迁移,并将数据播种到 MongoDB 数据库中。ts-migrate-mongoose 支持从 TypeScript 代码以及 CommonJS 代码运行迁移脚本。
ts-migrate-mongoose 是用于使用 mongoose 作为对象数据映射器的 Node.js 项目的迁移框架。它提供了编写迁移脚本的模板。它还提供了一个配置,以便从程序中运行脚本以及从 CLI 运行脚本。
目录
如何设置项目
要使用ts-migrate-mongoose进行数据库迁移,您需要具备以下条件:
-
一个安装了mongoose依赖的Node.js项目。
-
一个连接到项目的MongoDB数据库。
-
MongoDB Compass(可选 – 用于查看数据库中的更改)。
已创建了一个可从ts-migrate-mongoose-starter-repo克隆的入门存储库,以方便使用。克隆存储库,填写环境变量,并通过运行npm start
命令启动应用程序。
使用浏览器或诸如Postman之类的API客户端访问http://localhost:8000,服务器将返回一个“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数据库。此时,我们希望将用户数据种子到数据库中。我们需要:
-
创建一个用户集合(或表)
-
使用ts-migrate-mongoose创建一个迁移脚本来种子数据
-
使用ts-migrate-mongoose运行迁移以在应用程序启动之前将用户数据种子到数据库中
1. 使用 Mongoose 创建一个 users 集合
Mongoose 模式可以用来创建一个用户集合(或表)。用户文档(或记录)将包含以下字段(或列):email
、favouriteEmoji
和 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 为我们提供了 CLI 命令,用于运行迁移脚本的 up
和 down
函数。
使用 npx migrate up <script-名称>
,我们可以运行特定脚本的 up
函数。使用 npx migrate up
,我们可以运行位于数据库中具有 down
状态的 ./migrations
文件夹中所有脚本的 up
函数。
在应用程序启动之前运行迁移,我们利用 npm 脚本。带有前缀pre
的 npm 脚本将在没有pre
前缀的脚本之前运行。例如,如果有一个dev
脚本和一个predev
脚本,每当运行npm run dev
来运行dev
脚本时,predev
脚本将在dev
脚本运行之前自动运行。
我们将利用 npm 脚本的这一特性,将 ts-migrate-mongoose 命令放在prestart
脚本中,以便在运行start
脚本之前运行迁移。
更新package.json
文件,添加一个prestart
脚本,用于运行 ts-migrate-mongoose 命令以运行项目中迁移脚本的up
函数。
"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 分支,以查看本文当前时刻代码库的状态。
结论
在构建应用程序时,迁移非常有用,尤其是在需要为测试提供初始数据、填充管理用户、通过添加或删除列更新数据库架构,以及一次更新多个记录中的列值时。
如果您在 Node.js 应用程序中使用 Mongoose 和 MongoDB,ts-migrate-mongoose 可以帮助提供运行迁移的框架。
Source:
https://www.freecodecamp.org/news/handle-mongodb-migrations-with-ts-migrate-mongoose/