Как динамически подключить базу данных mysql в соответствии с каждым клиентом? - PullRequest
0 голосов
/ 30 мая 2018

Я создаю SaaS-продукт с использованием стека MEAN. M = mysql

Я использую sequelize в качестве ORM для mysql, мое соединение:

const sequelize = new Sequelize('smallscale_superapp', 'root', 'root1', {
  host: '127.0.0.1',
  port: 3306,
  dialect: 'mysql',
  logging: false,
});

Например, у меня есть один супер администраторприложение, поэтому я создаю один бизнес, например, бизнес-код с именем «001abcd», этот бизнес-код хранится в моей основной базе данных администратора, а затем я сказал всем своим клиентам перейти на один конкретный URL-адрес, называемый «example.com».

Так что, если они введут URL-адрес, домашняя страница будет выглядеть как slack.com, там будет одно поле ввода и после жестко закодированного значения example.com

Так что теперь мой клиент в поле ввода они помещаютбизнес-код, который я создал и сохранил в своей основной базе данных.

После помещения бизнес-кода в поле ввода откроется новый субдомен под названием «001abcd.example.com» (я проверяю, является ли бизнес-кодсовпадения в моей основной базе данных, если совпадает, я создаю динамические субдомены)

ТАК если все хорошо, после создания клиентской страницы субдомена будет отображаться экран входа в систему, где они должны зарегистрироваться, и детали регистрации должны быть там динамически, база данных

ПРИМЕЧАНИЕ : я получаю клиентскую базу данных, имя пользователя, хост, пароль в моей основной таблице базы данных при создании бизнеса.

Как это сделать с помощью sequelize mysql?

Как получить последовательное соединение для динамического подключения на основе логина клиента?

Как я уже говорил, у меня есть клиентское имя базы данных ... и т. Д. В моей базе данныхпытаясь создать соединение следующим образом:

exports.dynamicDatabase = (req, res) => {
  const { code } = req.params;
  Business.find({
    where: { code },
    raw: true,
  })
    .then((data) => {
      const sequelizeClient = new Sequelize(data.dbname, data.dbusername, data.dbpassword, {
        host: data.dbhost,
        port: 3306,
        dialect: 'mysql',
        logging: false,
      });
    })
    .catch((err) => { res.status(400).send(err.message); });
};

Теперь за пределами этой функции я пытаюсь синхронизировать таблицы, например:

sequelizeClient.authenticate().then((err) => {
  if (err) {
    console.log('There is connection in ERROR.');
  } else {
    console.log('Dynamic MYSQL Connection has been established successfully');
  }
});
sequelizeClient.sync().then(() => {
  console.log('Dynamic Missing Table Created');
}, (err) => {
  console.log('An error occurred while creating the table:', err.message);
});

Переменная sequelizeClient isвнутри функции, поэтому я не могу получить доступ?глобально.

Итак, я делаю переменную глобально, но есть одна проблема

У меня есть переменная sequelizeClient внутри функции, эта функция будет выполняться только после ввода моего домена в URL,

НоsequelizeClient.sync () не находится внутри функции, поэтому, когда я запускаю узел server.js, он выдает мне ошибку:

sequelizeClient.authenticate().then((err) => {
[0]                 ^
[0]
[0] TypeError: Cannot read property 'authenticate' of undefined

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

Да, после долгих поисков я обнаружил, что для создания продукта SaaS существует три подхода к базам данных:

  1. Отдельные базы данных для каждого арендатора
  2. Отдельные схемы (таблицы) иобщая одна база данных для всех арендаторов
  3. общие таблицы и одна база данных для всех арендаторов

Наконец, я решил использовать вариант 2 и перешел на Postgresql вместо mysql, потому что Postgresql имеет схемуоснованный подход!

Теперь мой окончательный код:

const postgresDB = new Sequelize('postgres://localhost:5432/test_enduser');

postgresDB.authenticate().then((err) => {
  if (err) {
    console.log('There is connection in ERROR.');
  } else {
    console.log('Postgres Connection has been established successfully');
  }
});

postgresDB.define('inventory', {
  name: Sequelize.STRING,
});

const createSchema = () => {
  Business.findAll({
    raw: true,
  }).then((data) => {
    data.forEach((client) => {
      postgresDB.createSchema(client.code).then(() => {
        Object.keys(postgresDB.models).forEach((currentItem) => {
          postgresDB.models[currentItem].schema(client.code).sync();
        });
        // new schema is created
        console.log('Postgres schema created');
      }).catch((err) => {
        console.log(err.message);
      });
    });
  });
};
createSchema();


// apis
exports.getAllBusiness = (req, res) => {
  postgresDB.models.inventory.schema(req.user.code).findAll()
    .then((results) => {
      res.send(results);
    });
};

exports.postBusiness = (req, res) => {
  const user = {
    name: req.body.name,
  };
  postgresDB.models.inventory.schema(req.user.code).create(user)
    .then(data => res.status(200).send(data))
    .catch(Sequelize.ValidationError, err => res.status(422).send(err.errors[0].message))
    .catch(err => res.status(400).send(err.message));
};
  1. Я устанавливаю свое соединение postgres
  2. Просто для теста я создаю таблицу под названием "инвентарь"
  3. В моем приложении пришла онлайн-заявка, и он зарегистрировался, а при регистрации я храню там Бизнес-код в моей таблице Business (Бизнес-таблица, поступающая из отдельной БД, которая является суперосновная база данных приложения), поэтому я нахожу бизнес-код, циклы и создаю динамические схемы в postgres

  4. Теперь посмотрите мой API, я делаю CRUD на основе req.user.code (изсеанс входа в систему)и я наконец сопоставляю показ данных в соответствии с конкретными схемами,

Итак, наконец, у меня есть чистые отдельные схемы для каждого клиента ?

Спасибо!

0 голосов
/ 31 мая 2018

Наконец я попробовал это и заставил это работать, но я не знаю, хороший ли это подход или нет, так скажите мне, хороший это подход или нет?

Я получаю точные данные по параметрам запроса пользователя:

let sequelizeClient;
let Login;
exports.getDomain = (req, res) => {
  const { code } = req.params;
  Business.find({
    raw: true,
    where: { code },
  }).then((data) => {
    if (data === null) {
      res.status(400).send(data);
    } else {
      sequelizeClient = new Sequelize(data.dbname, data.dbusername, data.dbpassword, {
        host: data.dbhost,
        port: 3306,
        dialect: 'mysql',
        logging: false,
      });

      // end user connections
      sequelizeClient.authenticate().then((err) => {
        if (err) {
          console.log('There is connection in ERROR.');
        } else {
          console.log(`${data.code} MYSQL Connection has been established successfully`);
        }
      });

      sequelizeClient.sync().then(() => {
        console.log(`${data.code} Missing Table Created`);
      }, (err) => {
        console.log('An error occurred while creating the table:', err.message);
      });

      // mysql tables;
      Login = sequelizeClient.define('login', {
        username: Sequelize.STRING,
        firstName: Sequelize.STRING,
        lastName: Sequelize.STRING,
      });
    }
  });
};

Я объявляю переменную схемы таблицы как глобальную и использую в своем коде:

// api
exports.signUp = (req, res) => {
  const user = {
    username: req.body.username,
    firstName: req.body.firstName,
    lastName: req.body.lastName,

  };
  Login.create(user)
    .then(data => res.status(200).send(data))
    .catch(Sequelize.ValidationError, err => res.status(422).send(err.errors[0].message))
    .catch(err => res.status(400).send(err.message));
};
...