如何正确处理猫鼬模式迁移?

Posted

技术标签:

【中文标题】如何正确处理猫鼬模式迁移?【英文标题】:How to properly handle mongoose schema migrations? 【发布时间】:2013-08-20 03:52:09 【问题描述】:

我对 MongoDB 和 Mongoose 完全陌生,似乎无法找到关于在架构更改时如何处理迁移的答案。

我习惯于运行迁移 SQL 脚本来更改表结构和任何需要更改的基础数据。这通常涉及数据库停机时间。

这通常在 MongoDB/Mongoose 中如何处理?有什么我需要注意的问题吗?

【问题讨论】:

您好,您解决了这个问题吗?我已经使用 mongoose 连接到 MongoDB,并且不想执行迁移。 我发布了一个简单的例子,逻辑在本地/现场环境中工作。 【参考方案1】:

在遇到这种情况并合理地理解迁移如何在关系数据库上工作时,MongoDB 使这变得更简单一些。我已经找到了两种方法来解决这个问题。在 MongoDB 中处理数据迁移时需要考虑的事项(在 RDB 中并不常见)是:

确保本地测试环境在开发人员合并项目存储库中的最新版本时不会中断 确保任何数据在实时版本上正确更新,无论用户是否登录或退出(如果使用身份验证)。 (当然,如果在升级时每个人都自动退出,那么只需要担心用户何时登录。

1) 如果您的更改将注销所有人或预计应用程序停机,那么执行此操作的简单方法是使用迁移脚本连接到本地或实时 MongoDB 并升级正确的数据。将用户名从单个字符串更改为具有给定和姓氏的对象的示例(当然非常基本,需要放入脚本中以供所有开发人员运行):

使用 CLI:

mongod
use myDatabase
db.myUsers.find().forEach( function(user)
    var curName = user.name.split(' '); //need some more checks..

    user.name = given: curName[0], family: curName[1];
    db.myUsers.save( user );
)

2) 您希望应用程序根据正在运行的应用程序版本上下迁移模式。这对于实时服务器来说显然会减轻负担,并且由于仅在用户第一次使用升级/降级版本时才升级用户,因此不需要停机时间。

如果您在 Expressjs 中为 Nodejs 使用中间件:

通过app.set('schemaVersion', 1) 在您的根应用脚本中设置一个应用变量,稍后将使用该变量与用户架构版本进行比较。 现在确保所有用户模式也具有 schemaVersion 属性,以便我们可以检测应用程序模式版本和当前 MongoDB 模式之间的变化,仅针对特定用户。

接下来我们需要创建简单的中间件来检测配置和用户版本

app.use( function( req, res, next )
  //If were not on an authenticated route
  if( ! req.user )
    next();
    return;
  
  //retrieving the user info will be server dependent
  if( req.user.schemaVersion === app.get('schemaVersion'))
    next();
    return;
  

  //handle upgrade if user version is less than app version

  //handle downgrade if user version is greater than app version

  //save the user version to your session / auth token / MongoDB where necessary
)

对于升级/降级,我会在迁移目录下创建简单的 js 文件,其中包含升级/降级导出函数,这些函数将接受用户模型并在 MongoDB 中对该特定用户运行迁移更改。最后确保用户版本在您的 MongoDB 中更新,这样他们就不会再次运行更改,除非他们再次移动到不同的版本。

【讨论】:

这是否意味着您可能对 MongoDB 中的每个模式都有一个中间件函数?这种方法的性能或其他权衡是什么? 这个答案非常具体到仅迁移用户的模型,但您将如何迁移其他模型。例如,假设您有一个在两个用户之间共享的 Match 模型,或者一个由用户创建但任何人都可以看到的 PublicEvent 模型?有哪些策略可以跨不同模型协调这些“实时迁移”,有些与特定用户相关,有些与特定用户无关? 此外,您可以在访问另一个模型时通过 populate() 调用引用用户记录。这个答案不考虑用户 A 在用户 B 登录之前引用填充用户 B 的数据并且他们的记录用户记录被更新的情况。因此,引用代码仍然必须以某种方式同时支持旧版本和新版本的模式。这可能分散在整个代码中,因此管理起来非常具有挑战性。希望看到有关人们如何管理此问题的更完整的答案(或博客文章)。【参考方案2】:

如果您习惯于 SQL 类型迁移或类似 Rails 的迁移,那么您会发现我的 cli 工具 migrate-mongoose 最适合您。

它允许您使用 updown 函数编写迁移,并根据迁移的成功和失败为您管理状态。

如果您使用 ES 2015 语法,它也支持 ES6。

您可以通过 this 对象访问您的 mongoose 模型,从而可以轻松地对模型和架构进行所需的更改。

【讨论】:

【参考方案3】:

有两种类型的迁移:

离线:将要求您停止服务进行维护,然后遍历整个集合并进行所需的更改。

在线:不需要停止服务进行维护。当您阅读该文档时,您会检查其版本,并针对新旧版本之间的每个版本运行特定于版本的迁移例程。然后你加载结果。

并非所有服务都能承受离线迁移,我推荐在线方法。

【讨论】:

以上是关于如何正确处理猫鼬模式迁移?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确处理猫鼬模式迁移?

如何使用猫鼬多次正确触发模式方法

如何使用 laravel 迁移和种子正确处理数据库数据更改

如何使用猫鼬正确塑造发送到 NodeJS 服务器的搜索日期

如何使用nestjs处理猫鼬错误

如何在猫鼬中为 geojson 数据创建模式?