自我引用与Objection.js的多对多关系

con*_*nny 3 node.js objection.js

我有CurrencyExchangeRate数据库表如下:

CREATE TABLE Currency (id INT, code VARCHAR(3), name TEXT);    
CREATE TABLE ExchangeRate (baseCurrencyId INT, counterCurrencyId INT, rate FLOAT);

INSERT INTO Currency (id, code, name) VALUES 
  (1, 'USD', 'US Dollars'),
  (2, 'AUD', 'Australian Dollars');
INSERT INTO ExchangeRate (baseCurrencyId, counterCurrencyId, rate) VALUES
  (1, 2, 1.342),
  (2, 1, 0.745);
Run Code Online (Sandbox Code Playgroud)

给定baseCurrency Currency.id和counterCurrency Currency.code,我想找到相应的exchange rate counterCurrency name.

建模这种关系的最有效方法是什么?(我使用的是Objection.js v0.4.0)

Mik*_*stö 5

我在表名和列名中添加引号以使它们区分大小写:

CREATE TABLE "Currency" (
  id INT, code VARCHAR(3), name TEXT
);    
CREATE TABLE "ExchangeRate" (
  "baseCurrencyId" INT, "counterCurrencyId" INT, rate FLOAT
);

INSERT INTO "Currency" (id, code, name) VALUES 
  (1, 'USD', 'US Dollars'),
  (2, 'AUD', 'Australian Dollars');
INSERT INTO "ExchangeRate" ("baseCurrencyId", "counterCurrencyId", rate) VALUES
  (1, 2, 1.342),
  (2, 1, 0.745);
Run Code Online (Sandbox Code Playgroud)

您可以建模多个到多个关系,其中存储在连接表中的额外参数:

const knex = require('knex')({ 
  client: 'pg', 
  connection: 'postgres:///objection_test'
});
const { Model } = require('objection');
const Promise = require('bluebird');

class Currency extends Model {

  static get tableName() { return 'Currency'; }

  static get relationMappings() {
    return {
      currencyWithRate: {
        relation: Model.ManyToManyRelation,
        modelClass: Currency,
        join: {
          from: 'Currency.id',
          through: {
            from: 'ExchangeRate.baseCurrencyId',
            to: 'ExchangeRate.counterCurrencyId',
            extra: ['rate']
          },
          to: 'Currency.id'
        }
      }
    };
  }
}

const boundModel = Currency.bindKnex(knex);

boundModel.query().then(currencies => {
  // get related currencies for each 
  return Promise.all(currencies.map(cur => {
    return Promise.join(cur, cur.$relatedQuery('currencyWithRate'),
      (cur, exchangeRateCurrency) => {
        return {
          currency: cur,
          exchangeRateCurrency: exchangeRateCurrency
        };
      });
  }));
}).then(result => {
  console.dir(result, { depth: null});
}).finally(() => {
  return knex.destroy();
});
Run Code Online (Sandbox Code Playgroud)

让我们假设上面的代码是test.js:

Mikaels-MacBook-Pro-2: mikaelle$ node test.js 
[ { currency: 
     AnonymousModelSubclass {
       id: 1,
       code: 'USD',
       name: 'US Dollars',
       currencyWithRate: [ AnonymousModelSubclass { id: 2, code: 'AUD', name: 'Australian Dollars', rate: 1.342 } ] },
    exchangeRateCurrency: [ AnonymousModelSubclass { id: 2, code: 'AUD', name: 'Australian Dollars', rate: 1.342 } ] },
  { currency: 
     AnonymousModelSubclass {
       id: 2,
       code: 'AUD',
       name: 'Australian Dollars',
       currencyWithRate: [ AnonymousModelSubclass { id: 1, code: 'USD', name: 'US Dollars', rate: 0.745 } ] },
    exchangeRateCurrency: [ AnonymousModelSubclass { id: 1, code: 'USD', name: 'US Dollars', rate: 0.745 } ] } ]
Mikaels-MacBook-Pro-2: mikaelle$ 
Run Code Online (Sandbox Code Playgroud)

看起来$relatedQuery()也是查询Model请求其关系的查询对象.