Hi,

Мы планируем создать мультитенантный продукт SaaS.

Подождите, что называется мультитенантным и SaaS? - Пожалуйста, погуглите 🙏🏼

Сначала мы проектируем прототип приложения. Дизайн классный. 😍

Во-вторых, мы планируем это реализовать.

Изначально мы выбираем стек MEAN для создания этого продукта вместо «Mongo», мы выбираем «MySQL» 😌

Но мы не знаем, как спроектировать архитектуру базы данных с несколькими арендаторами. Мы запутались.

Позже мы погуглили «как построить, как реализовать, как… ..»

Наконец-то у нас появилась идея!

Существует три основных распространенных архитектуры для создания мультитенантного приложения.

  1. Отдельная база данных для каждого клиента
  2. Одна база данных, но отдельная таблица для каждого клиента
  3. Единая база данных и одни и те же таблицы для всех клиентов, но у нас есть tenant_id во всех таблицах, поэтому мы запрашиваем данные в соответствии с конкретным клиентом.

Выбираем вариант 2.

И снова мы погуглили, «как создавать отдельные таблицы для каждого клиента в MySQL».

К тому времени мы обнаружили, что в Postgres есть концепция под названием «схемы» - единая база данных, внутри которой мы можем создавать несколько схем, называемых client1schema, client2schema… и т. Д. Внутри этих схем у нас есть отдельные таблицы.

ИДЕАЛЬНО 🔥

Итак, наконец, мы начали писать код.

Как создавать динамические схемы?

В мою заявку входит новый пользователь, он вводит данные для регистрации

имя пользователя, электронная почта, пароль, телефон.

Мы получаем детали с помощью AngularJs, поэтому мы отправляем эти данные на мой экспресс-сервер.

Код AngularJs:

$http.post('/api/signup/', datas)
 .then(() => { })
 .catch(() => { });

узел / экспресс:

app.post('/api/signup', api.signup);

Структуры таблиц и подключение к базе данных:

// Table structures
// client app postgres
const db = new Sequelize(config.postgres_db, config.postgres_user, config.postgres_pwd, {
  host: config.postgres_host,
  port: 5432,
  dialect: 'postgres',
  logging: false,
});
db.authenticate().then((err) => {
  if (err) {
    console.log('There is connection in ERROR.');
  } else {
    console.log('Postgres Client App Connection has been established successfully');
  }
});
db.sync().then(() => {
  console.log('Psql Client App Missing Table Created');
}, (err) => {
  console.log('An error occurred while creating postgres client app table:', err.message);
});
const Business = db.define('business', {
  username: Sequelize.STRING,
});
const Login = db.define('login', {
  username: Sequelize.STRING,
  email: Sequelize.STRING,
  mobile: Sequelize.STRING,
  password: Sequelize.STRING,
});
exports.signup = (req, res) => {
  // in req.body i have all details 'name, email....';
  // now checking whether username already exists or not.
  Business.findOrCreate({
    where: {
      username: req.body.username,
    },
    defaults: {
      username: req.body.username,
    },
  }).spread((user, created) => {
    if (created) {
      createSchema(req, res); // function
    } else {
      res.status(400).send(`${req.body.username} already exists.`);
    }
  }).catch(err => res.status(400).send(err.message));
};

// This below function will create schema dynamically.
const createSchema = async (req, res) => {
  await db.createSchema(req.body.username).then(async () => {
    await Object.keys(db.models).forEach((currentItem) => {
      db.models[currentItem].schema(req.body.username).sync();
    });
    const loginDetails = {
      username: req.body.username,
      password: encrypt(req.body.password),
      email: req.body.email,
      mobile: req.body.mobile,
    };
    const loginSchema = db.models.login.schema(req.body.username);
    loginSchema.create(loginDetails)
      .then((loginData) => {
        res.status(200).send(loginData);
      })
      .catch((err) => { console.log('error :', err.message); });
  });
};

Например, если имя пользователя введено как «sameer», создается схема с именем «sameer».

Подключите базу данных psql через командную строку и нажмите \ dn.

Да, у нас есть схема под названием «sameer» с отдельными таблицами.

выберите * из sameer.logins; вы увидите подробности.

Теперь, как динамически получить конкретную схему определенных пользователей?

Перейдем к разделу входа:

Теперь пользователь переходит в раздел входа в систему, теперь он вводит имя пользователя и пароль и нажимает кнопку входа в систему!

Я использую password.js для аутентификации.

// login passport api
exports.Login = (req) => {
  console.log(req.body.username); // sameer
  db.models.login.schema(req.body.username).find({
    where: {
      username: req.body.username,
    },
    raw: true,
  }).then(() => {
    // your stuffs....logics...
  })
};

Эй, вот и все, что у нас получилось!

у нас есть сеанс req.user в паспорте.js.

Итак, если вы хотите использовать операции CRUD с помощью Sequelize

вместо использования Table.create или Table.find и т. д.

Используйте этот формат ниже

db.models.table.schema(req.user.username).create( ... your logics )
db.models.table.schema(req.user.username).find(... your logics)
db.models.table.schema(req.user.username).update(... your logics)
db.models.table.schema(req.user.username).update(... your logics)

Спасибо за прочтение :)