如何在 Loopback 中自动迁移
How to automigrate in Loopback
我在我的环回应用程序中重命名了许多模型和表,但是我现在必须迁移到这个模型定义。
我需要 运行 autoMigrate()。它必须是 运行 在 dataSource 对象上,但文档没有提供有关获取其中之一的帮助。
到目前为止,我已经在 /boot
中创建了一个新脚本,其中包含:
var loopback = require('loopback');
var app = module.exports = loopback();
app.loopback.DataSource.automigrate()
但此数据源对象不包含 autoMigrate 函数...
我已尝试 运行ning 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)
我只需要更新模型,不明白为什么这么难。有谁知道如何克服这些障碍?谢谢!
您需要在启动脚本中使用 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
两个问题。
首先,您显示的是 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.
在 bin 目录的服务器文件夹中创建一个新文件(automigrate.js),并将以下代码粘贴到该文件中。在这里,我使用 cassandra 作为数据源并在 table 中插入虚拟数据。您可以将此代码用于不同的数据源。根据您自己的要求更改 table 架构。
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 存储库。
我真的很喜欢 runs autoupdate on each model one at a time so I can know which ones were updated. Unfortunately it iterates over app.model
which is incorrect and can have some negative side effects。
这是我的版本(async/await 需要 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();
});
});
}
我在我的环回应用程序中重命名了许多模型和表,但是我现在必须迁移到这个模型定义。
我需要 运行 autoMigrate()。它必须是 运行 在 dataSource 对象上,但文档没有提供有关获取其中之一的帮助。
到目前为止,我已经在 /boot
中创建了一个新脚本,其中包含:
var loopback = require('loopback');
var app = module.exports = loopback();
app.loopback.DataSource.automigrate()
但此数据源对象不包含 autoMigrate 函数...
我已尝试 运行ning 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)
我只需要更新模型,不明白为什么这么难。有谁知道如何克服这些障碍?谢谢!
您需要在启动脚本中使用 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
两个问题。
首先,您显示的是 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.
在 bin 目录的服务器文件夹中创建一个新文件(automigrate.js),并将以下代码粘贴到该文件中。在这里,我使用 cassandra 作为数据源并在 table 中插入虚拟数据。您可以将此代码用于不同的数据源。根据您自己的要求更改 table 架构。
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 存储库。
我真的很喜欢app.model
which is incorrect and can have some negative side effects。
这是我的版本(async/await 需要 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();
});
});
}