我很难理解与多个开发人员、多个环境一起扩展数据库迁移的正确方法,包括使用 ts-migrate-mongoose 的许多用户的生产数据库。 github 中提供的示例非常简单,并没有真正展示如何使用不断发展的模式进行迁移。它只是有一个静态模式,并运行迁移以使用一些初始数据填充数据库,而且我也无法在网上找到任何真实的示例。
让我们以经典示例为例并对其进行扩展。可以说我有
interface IUser {
_id: string;
name: string;
}
const User = new Schema<IUser>({
_id: { type: String, required: true },
name: { type: String, required: true }
})
我想将其更新为:
interface IUser {
_id: string;
firstName: string;
lastName: string;
}
const User = new Schema<IUser>({
_id: { type: String, required: true },
firstName: { type: String, required: true },
lastName: { type: String, required: true }
})
我可以写一些迁移,比如
const up = async () => {
const users = await User.find();
const updates = users.map((user) => {
const firstName = user.name.split(" ")[0];
const lastName = user.name.split(" ")[1];
return user.updateOne({$set: {firstName, lastName}})
});
await Promise.all(updates)
};
const down = async () => {
// ... corresponding down migration
}
但是当我更改接口和模型定义时,这将开始给我带来类型错误。然后可以说,我还有更多的迁移,为了举例,假设我正在进行第五次迁移,并且我有一个开发人员回到了第一次迁移。现在我可以为每个迁移文件定义新的模式和模型,但如果进行多个迁移,我开始收到错误:
Cannot overwrite `User` model once compiled.
一个可能的解决方案是添加:
delete (mongoose.connection.models as any)["User"];
位于迁移文件的顶部。但这真的是解决这个问题的最佳方法吗?实际上只是寻找一些关于如何使用不断发展的模式进行这些数据库迁移的一般建议。如果需要任何说明,请告诉我。谢谢
有一种方法可以动态设置 migrate-mongo 的配置。
import * as migrateMongo from 'migrate-mongo';
@Injectable()
export class CustomMigrationService {
const dynamic_configuration = this.generateConfig("your_mongo_url", "your_changelog_dir_path");
await migrateMongo.config.set(dynamic_configuration);
const { db, client } = await migrateMongo.database.connect();
await migrateMongo.up(db, client);
}
其中“dynamic_configuration”是具有 migrate-mongo 配置结构的对象。
private generateConfig(mongoUrl: string, changelogFilesDir: string) {
return {
mongodb: {
url: mongoURL,
options: {
auth: {
//based on requirements
}
},
},
migrationsDir: changelogFilesDir,
//collection name in the database
changelogCollectionName: "changelog",
migrationFileExtension: '.js',
//Do not change this unless you know what you are doing
moduleSystem: 'esm',
useFileHash: false
};
}