【问题标题】:How to automigrate in Loopback如何在 Loopback 中自动迁移
【发布时间】:2019-05-26 00:12:14
【问题描述】:

我已经重命名了我的环回应用程序中的一些模型和表,但是我现在必须迁移到这个模型定义。

我需要运行autoMigrate()。它必须在 dataSource 对象上运行,但文档没有提供有关获取其中之一的帮助。

到目前为止,我已经在 /boot 中创建了一个新脚本,其中包含:

var loopback = require('loopback');
var app = module.exports = loopback();
app.loopback.DataSource.automigrate()

但此数据源对象不包含 autoMigrate 函数...

我尝试运行 strongloop arc 来使用那里的自动迁移按钮,但页面崩溃并出现以下错误:

Uncaught Error: [$injector:modulerr] Failed to instantiate module Arc due to:
Error: [$injector:modulerr] Failed to instantiate module Metrics due to:
Error: [$injector:nomod] Module 'Metrics' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.3.20/$injector/nomod?p0=Metrics
    at http://localhost:56073/scripts/vendor/angular/angular.js:63:12
    at http://localhost:56073/scripts/vendor/angular/angular.js:1778:17
    at ensure (http://localhost:56073/scripts/vendor/angular/angular.js:1702:38)
    at module (http://localhost:56073/scripts/vendor/angular/angular.js:1776:14)
    at http://localhost:56073/scripts/vendor/angular/angular.js:4131:22
    at forEach (http://localhost:56073/scripts/vendor/angular/angular.js:326:20)
    at loadModules (http://localhost:56073/scripts/vendor/angular/angular.js:4115:5)
    at http://localhost:56073/scripts/vendor/angular/angular.js:4132:40
    at forEach (http://localhost:56073/scripts/vendor/angular/angular.js:326:20)
    at loadModules (http://localhost:56073/scripts/vendor/angular/angular.js:4115:5)
http://errors.angularjs.org/1.3.20/$injector/modulerr?p0=Metrics&p1=Error%3…F%2Flocalhost%3A56073%2Fscripts%2Fvendor%2Fangular%2Fangular.js%3A4115%3A5)
    at http://localhost:56073/scripts/vendor/angular/angular.js:63:12
    at http://localhost:56073/scripts/vendor/angular/angular.js:4154:15
    at forEach (http://localhost:56073/scripts/vendor/angular/angular.js:326:20)
    at loadModules (http://localhost:56073/scripts/vendor/angular/angular.js:4115:5)
    at http://localhost:56073/scripts/vendor/angular/angular.js:4132:40
    at forEach (http://localhost:56073/scripts/vendor/angular/angular.js:326:20)
    at loadModules (http://localhost:56073/scripts/vendor/angular/angular.js:4115:5)
    at createInjector (http://localhost:56073/scripts/vendor/angular/angular.js:4041:11)
    at doBootstrap (http://localhost:56073/scripts/vendor/angular/angular.js:1455:20)
    at bootstrap (http://localhost:56073/scripts/vendor/angular/angular.js:1476:12)
http://errors.angularjs.org/1.3.20/$injector/modulerr?p0=Arc&p1=Error%3A%20…%2Flocalhost%3A56073%2Fscripts%2Fvendor%2Fangular%2Fangular.js%3A1476%3A12)

我只需要更新模型,不明白为什么这么难。有人知道如何克服这些障碍吗?谢谢!

【问题讨论】:

    标签: loopbackjs strongloop loopback


    【解决方案1】:

    两个问题。

    首先,您显示的是 Angular 客户端错误,而您的问题出在服务器端。

    现在,回到问题的核心。

    启动脚本必须导出一个函数,在同步启动脚本的情况下,该函数将只接受环回对象(您的服务器),或者在异步启动脚本的情况下接受回送对象和回调。

    编写启动脚本已记录在案here

    函数datasource.automigrate可以同步调用。 如果您不带参数调用它,默认情况下它将为您应用中的所有模型执行,这很可能是您想要的。

    因此,如果您定义的数据库名称为 mysql(在 ./server/datasources.json 中定义),则启动脚本为:

    module.exports = function (app) {
       app.dataSources.mysql.automigrate();
       console.log("Performed automigration.");
    }
    

    您可以通过运行node .NOT 来检查这是否有效,方法是在您的浏览器中访问服务器正在侦听的地址。 (您的 Angular 相关错误与启动脚本无关,它与客户端文件有关,很可能位于 client 文件夹中)。

    它应该显示在终端中

    Performed automigration.
    

    【讨论】:

      【解决方案2】:

      我真的很喜欢 Jesé Rodríguez's answer 如何在每个模型上一次运行一个自动更新,这样我就可以知道哪些模型被更新了。不幸的是,它迭代了不正确的app.modelcan have some negative side effects

      这是我的版本(异步/等待需要 Node 8+):

      'use strict';
      
      // Update (or create) database schema (https://loopback.io/doc/en/lb3/Creating-a-database-schema-from-models.html)
      // This is effectively a no-op for the memory connector
      module.exports = function(app, cb) {
        updateDatabaseSchema(app).then(() => {
          process.nextTick(cb);
        });
      };
      
      async function updateDatabaseSchema(app) {
        const dataSource = app.dataSources.db;
      
        for (let model of app.models()) {
          if (await doesModelNeedUpdate(dataSource, model.modelName) === true) {
            await updateSchemaForModel(dataSource, model.modelName);
          }
        }
      }
      
      function doesModelNeedUpdate(dataSource, model) {
        return new Promise((resolve, reject) => {
          dataSource.isActual(model, (err, actual) => {
            if (err) reject(err);
            resolve(!actual);
          });
        });
      }
      
      function updateSchemaForModel(dataSource, model) {
        return new Promise((resolve, reject) => {
          dataSource.autoupdate(model, (err, result) => {
            if (err) reject(err);
            console.log(`Autoupdate performed for model ${model}`);
            resolve();
          });
        });
      }
      

      【讨论】:

        【解决方案3】:

        您需要在引导脚本中使用app.dataSources.<dataSourceName> 而不是app.loopback.DataSource

        在你的启动脚本中试试这个:

        module.exports = function (app) {
        'use strict'
        var mysql = app.dataSources.mysql;
        
        console.log('-- Models found:', Object.keys(app.models));
        
        for (var model in app.models) {
            console.log("Cheking if table for model " + model + " is created and up-to-date in DB...");
            mysql.isActual(model, function (err, actual) {
                if (actual) {
                    console.log("Model " + model + " is up-to-date. No auto-migrated.");
                } else {
                    console.log('Difference found! Auto-migrating model ' + model + '...');
                    mysql.autoupdate(model, function () {
                        console.log("Auto-migrated model " + model + " successfully.");
                    });
                }
            });
        } };
        

        你可以在 GitHub 上看到一个基本示例:https://github.com/jeserodz/loopback-models-automigration-example

        【讨论】:

        • 感谢您的回复,但运行它给了我:
        • 感谢您的回复,但是运行它给了我TypeError: Cannot read property 'settings' of undefined
        • var mysql = app.dataSources.mysql; 应更改为您的数据源的名称。您的模型在 server/model-config.json 上使用的相同。
        • 是的,我在我的版本中用 postgresql 替换了所有提到的 mysql,这产生了错误。错误指向.isActual这一行,可能连接的postgres不支持这个功能
        • 这对于执行自动迁移来说太复杂了。 See my answer,您不需要传递模型列表来自动迁移,默认情况下它将为所有人运行。因为你是新来的,所以我不会反对
        【解决方案4】:

        在 bin 目录的 server 文件夹中创建一个新文件(automigrate.js),并将以下代码粘贴到该文件中。在这里,我使用 cassandra 作为数据源并在表中插入虚拟数据。您可以将此代码用于不同的数据源。根据您自己的要求更改表架构。

        var path = require('path');
        var app = require(path.resolve(__dirname, '../server/server'));
        var ds = app.datasources.cassandra;
        ds.automigrate('dataSourceTesting', function(err) {
          if (err) throw err;
        
          var accounts = [
            {
              name: 'john.doe@ibm.com',
              address: "asdasd"
            },
            {
              name: 'jane.doe@ibm.com',
              address: "asdasdasd"
            },
          ];
          var count = accounts.length;
          accounts.forEach(function(account) {
            app.models.dataSourceTesting.create(account, function(err, model) {
              if (err) throw err;
        
              console.log('Created:', model);
        
              count--;
              if (count === 0)
                ds.disconnect();
            });
          });
        });
        

        代码来源:loopback github 仓库。

        【讨论】:

          猜你喜欢
          • 2015-07-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-24
          • 2020-03-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多