loopbackjs:将一个模型,不同的数据源

问题描述 投票:8回答:3

我已经定义了使用数据源“DB”(MySQL的)我的环境几款机型。

有什么办法有连接到那些模型多个数据源,所以我将能够执行REST操作到不同的数据库?

即:GET / API / DS的事情= “DB”?

GET / API /事呢?DS = “anotherdb”

GET / API /事(将使用默认DS)

node.js loopbackjs strongloop
3个回答
6
投票

正如@superkhau上面所指出的,每个环回模式可以连接到仅单个数据源。

您可以创建(子类)为您要使用的每个数据源的新模式。然后,您可以通过独特的REST的URL揭露这些每个数据源的模型,也可以实现一个包装模式,将派遣方式到正确的数据源特定的模型。

在我的例子中,我将介绍如何暴露每个数据源模型是连接到Cardb一个anotherdb模型。该Car模型是在通过common/models/car.jsoncommon/models/car.js通常的方式来定义。

现在,你需要定义每个数据源模型:

// common/models/car-db.js
{
  "name": "Car-db",
  "base": "Car",
  "http": {
    "path": "/cars:db"
  }
}

// common/models/car-anotherdb.js
{
  "name": "Car-anotherdb",
  "base": "Car",
  "http": {
    "path": "/cars:anotherdb"
  }

}

// server/model-config.json
{
  "Car": {
    "dataSource": "default"
  },
  "Car-db": {
    "dataSource": "db"
  },
  "Car-anotherdb": {
    "dataSource": "anotherdb"
  }
}

现在,您有以下网址提供:

GET /api/Cars:db
GET /api/Cars:anotherdb
GET /api/Cars

上述解决方案有两个限制:你必须定义每个数据源的新模式和数据源不能使用查询参数进行选择。

为了解决这个问题,你需要不同的方法。我会再假设有已定义的Car模型。

现在,你需要创建一个“调度员”。

// common/models/car-dispatcher.json
{
  "name": "CarDispatcher",
  "base": "Model", //< important!
  "http": {
    "path": "/cars"
  }
}

// common/models/car-dispatcher.js
var loopback = require('loopback').PersistedModel;
module.exports = function(CarDispatcher) {
  Car.find = function(ds, filter, cb) {
    var model = this.findModelForDataSource(ds);
    model.find(filter, cb);
  };

  // a modified copy of remoting metadata from loopback/lib/persisted-model.js
  Car.remoteMethod('find', {
    isStatic: true,
    description: 'Find all instances of the model matched by filter from the data source',
    accessType: 'READ',
    accepts: [
     {arg: 'ds', type: 'string', description: 'Name of the datasource to use' },
     {arg: 'filter', type: 'object', description: 'Filter defining fields, where, orderBy, offset, and limit'}
    ],
    returns: {arg: 'data', type: [typeName], root: true},
    http: {verb: 'get', path: '/'}
  });

  // TODO: repeat the above for all methods you want to expose this way

  Car.findModelForDataSource = function(ds) {
    var app = this.app;
    var ds = ds && app.dataSources[ds] || app.dataSources.default;

    var modelName = this.modelName + '-' + ds;
    var model = loopback.findModel(modelName);
    if (!model) {
      model = loopback.createModel(
        modelName, 
        {},
        { base: this.modelName });
    }

    return model;
  };  
};

最后一点是去除Car和模型配置使用CarDispatcher

// server/model-config.json
{
  "CarDispatcher": {
    dataSource: null,
    public: true
  }
}

1
投票

默认情况下,你只能在每个模型基础上附加的数据源。这意味着你可以通过datasources.json每个模型连接到不同的数据源。

为了您的使用情况,您会添加一个远程钩子向每个端点你想为多个数据源。在远程钩子,你会做这样的事情:

...
var ds1 = Model.app.dataSources.ds1;
var ds2 = Model.app.dataSources.ds2;

//some logic to pick a data source
if (context.req.params...
...

http://docs.strongloop.com/display/LB/Remote+hooks获取更多信息。


0
投票

对于任何人还在找工作答案,在飞行切换数据库的解决办法是写检查请求的路径,然后创建一个新的数据源的连接器,传递一个变量基础上,req.path变量中间件脚本。例如,如果请求路径是/订单,然后“订单”作为字符串将被保存在变量,那么,我们连接一个新的数据源,在该变量中传递“订单”。下面是完整的工作代码。

'use strict';

const DataSource = require('loopback-datasource-juggler').DataSource;
const app = require('../server.js');

module.exports = function() {
  return function datasourceSelector(req, res, next) {
  // Check if the API request path contains one of our models.
  // We could use app.models() here, but that would also include
  // models we don't want.
  let $models = ['offers', 'orders', 'prducts'];
  // $path expects to be 'offers', 'orders', 'prducts'.
  let $path = req.path.toLowerCase().split("/")[1];

  // Run our function if the request path is equal to one of
  // our models, but not if it also includes 'count'. We don't
  // want to run this twice unnecessarily.
  if (($models.includes($path, 0)) && !(req.path.includes('count'))) {
    // The angular customer-select form adds a true value
    // to the selected property of only one customer model.
    // So we search the customers for that 'selected' = true.
    let customers = app.models.Customer;
    // Customers.find() returns a Promise, so we need to get
    // our selected customer from the results.
    customers.find({"where": {"selected": true}}).then(function(result){
      // Called if the operation succeeds.
      let customerDb = result[0].name;
      // Log the selected customer and the timestamp
      // it was selected. Needed for debugging and optimization.
      let date = new Date;
      console.log(customerDb, $path+req.path, date);
      // Use the existing veracore datasource config
      // since we can use its environment variables.
      let settings = app.dataSources.Veracore.settings;
      // Clear out the veracore options array since that
      // prevents us from changing databases.
      settings.options = null;
      // Add the selected customer to the new database value.
      settings.database = customerDb;
      try {
        let dataSource = new DataSource(settings);
        // Attach our models to the new database selection.
        app.models.Offer.attachTo(dataSource);
        app.models.Order.attachTo(dataSource);
        app.models.Prduct.attachTo(dataSource);
      } catch(err) {
        console.error(err);
      }
    })
    // Called if the customers.find() promise fails.
    .catch(function(err){
      console.error(err);
    });
  }
  else {
    //  We need a better solution for paths like '/orders/count'.
    console.log(req.path + ' was passed to datasourceSelector().');
  }
  next();
  };
};
© www.soinside.com 2019 - 2024. All rights reserved.