Создание ассоциаций между 2 таблицами в 2 разных базах данных с разным хостом / сервером — ER_BAD_DB_ERROR

#javascript #node.js #express #sequelize.js #sequelize-cli

#javascript #node.js #экспресс #sequelize.js #sequelize-cli

Вопрос:

У меня есть 2 разные базы данных, на 2 разных серверах, с 2 разными схемами.

По сути, я хочу связать одну таблицу в одной базе данных с другой таблицей в другой базе данных, хотя у меня возникают некоторые проблемы с этим. Мне удалось создать ассоциации между 2 таблицами в 2 разных базах данных на одном сервере, возникли проблемы, когда они не используют один и тот же хост / сервер.

Я не совсем уверен, что это вообще возможно, но я надеюсь, что есть способ обойти это?

Ниже приведена моя архитектура, в которой указаны 2 сервера, 2 базы данных и отсутствует связь между property amp; favourites

      -------------------- -------------------- 
    | Server-1           |           Server-2 |
     -------------------- -------------------- 
    | Database-1         |         Database-2 |
     -------------------- -------------------- 
    | property  <----------------- favourites |
    | user               |         notes      |
    | account            |                    |
     -------------------- -------------------- 
  

Я следил за этой статьей в качестве отправной точки, хотя она, к сожалению, не охватывает мой вариант использования.

Вот моя конфигурация, определяющая параметры, полученные из файла среды и

config.js

 import accessEnv from "../utils/accessEnv";
import logger from "../utils/logger";

const defaultOptions = {
  dialect: "mysql",
  logging: msg => logger.debug(msg)
};

module.exports = {
  /**Declaration of databases for my development environment**/
  "development": {
    "databases": {
      "Database1": {
        "database": accessEnv("DB"),
        "username": accessEnv("DB_USERNAME"),
        "password": accessEnv("DB_PASS"),
        "host": accessEnv("DB_HOST"),
        "port": accessEnv("DB_PORT"),
        ...defaultOptions
      },
      "Database2": {
        "database": accessEnv("DB2"),
        "username": accessEnv("DB2_USERNAME"),
        "password": accessEnv("DB2_PASS"),
        "host": accessEnv("DB2_HOST"),
        "port": accessEnv("DB2_PORT"),
        ...defaultOptions
      },
    },
  }
}
  

в моем продолжении, созданном index.js для моих моделей, я немного обновил его, основываясь на статье, указанной выше, для обработки 2 разных подключений к базе данных.

models/index.js

 const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const { default: logger } = require('../utils/logger');
const basename = path.basename(module.filename);
const env = process.env.NODE_ENV || 'development';
const config = require(`${__dirname}/../config/config.js`)[env];
const db = {};
const databases = Object.keys(config.databases);

/** Add Databases**/
for (let i = 0; i < databases.length;   i) {
  let database = databases[i];
  let dbPath = config.databases[database];
  db[database] = new Sequelize(dbPath.database, dbPath.username, dbPath.password, dbPath);
  // Authenticate db connection
  db[database].authenticate()
    .then(() => logger.log(`${dbPath.database} connection successful!`))
    .catch((err) => logger.log(err.stack));
  // Allow schemas
  db[database].dialect.supports.schemas = true;
}

/**Add the Database Models**/
// Add models from database1 folder
fs
  .readdirSync(__dirname   '/database1')
  .filter(file =>
    (file.indexOf('.') !== 0) amp;amp;
    (file !== basename) amp;amp;
    (file.slice(-3) === '.js'))
  .forEach(file => {
    const model = require(path.join(__dirname   '/database1', file))(db.Database1, Sequelize.DataTypes);
    db[model.name] = model;
  });

// Add models from database2 folder
 fs
  .readdirSync(__dirname   '/database2')
  .filter(file =>
    (file.indexOf('.') !== 0) amp;amp;
    (file !== basename) amp;amp;
    (file.slice(-3) === '.js'))
  .forEach(file => {
    const model = require(path.join(__dirname   '/database2', file))(db.Database2, Sequelize.DataTypes);
    db[model.name] = model;
  });

Object.keys(db).forEach(modelName => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

module.exports = db;
  

Now for the models themselves.

  • Property is in one server with the Database1 config.
  • Favourites is in another server with the Database2 config.

A Favourites will have one Property , associating by a foreignKey of propertyId in the Favourites model to id of Property model.

models/database1/Property.js

 module.exports = (sequelize, DataTypes) => {
  const Property = sequelize.define("Property", {
    id: {
      type: DataTypes.INTEGER(11),
      primaryKey: true,
      allowNull: false,
      autoIncrement: true
    },
    accountNumber: {
      type: DataTypes.STRING(9),
      allowNull: false,
    }
  }, {
    schema: "property_demo",
    tableName: "property",
  });
  Property.associate = (models) => {
    Property.hasOne(models.Favourites, {
      as: 'favourites',
      foreignKey: 'propertyId'
    });
  };
  return Property;
};
  

models/database2/Favourites.js

 module.exports = (sequelize, DataTypes) => {
  const Favourites = sequelize.define("Favourites", {
    id: {
      type: DataTypes.INTEGER(),
      primaryKey: true,
      allowNull: false,
      autoIncrement: true
    },
    propertyId: {
      type: DataTypes.INTEGER(11),
      allowNull: false,
    }
  }, {
    schema: "shortlists",
    tableName: "favourites"
  });
  Favourites.associate = (models) => {
    Favourites.belongsTo(models.Property, {
      as: 'property',
      foreignKey: 'propertyId'
    });
  };
  return Favourites;
};
  

Теперь, в чем проблема. Когда я пытаюсь include Property использовать модель в Favourites запросе модели, как показано ниже

 import catchAsync from "../utils/catchAsync";
import Models, { Favourites } from "../models";

export const getFavourites = catchAsync(async (req, res, next) => {
  const favourites = await Favourites.findAll({
    include: [
      {
        model: Models.Property,
        as: 'property',
      }
    ]
  });
  
  return res.status(200).json({
    status: 'success',
    data: favourites
  });

});
  

Я получаю следующую ошибку

 "error": {
  "name": "SequelizeDatabaseError",
  "parent": {
    "code": "ER_BAD_DB_ERROR",
    "errno": 1049,
    "sqlState": "42000",
    "sqlMessage": "Unknown database 'property_demo'"
  }
}
  

Я понимаю, что он ищет property_demo on Server-2 , поскольку Favourites модель основана на Server-2 , несмотря Property на то, что модель находится в property_demo схеме on Server-1 , но есть ли способ обойти это, чтобы он фильтровал правильный сервер / хост здесь?

Любая помощь будет принята с благодарностью.

Комментарии:

1. Можете ли вы выполнить такой запрос как обычный SQL-запрос?

2. MySQL не был бы моей сильной стороной, поэтому я не уверен, кроме использования ОБЪЕДИНЕННОЙ таблицы

3. В этом суть! Sequelize не может сам смешивать таблицы с двух разных серверов

4. Просто возвращаюсь к этому, добавляя separate: true, в качестве опции включение для Property работ, если я изменю ассоциацию Favourites.hasMany(models.Property amp; set sourceKey: 'propertyId'