如何根据每个客户端动态连接mysql数据库?

时间:2018-05-30 09:16:37

标签: javascript mysql node.js sequelize.js saas

我正在使用MEAN堆栈构建SaaS产品M = mysql

我正在使用sequelize作为mysql的ORM,我的连接:

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

例如,我有一个管理员超级应用程序,所以我创建一个业务,例如业务代码调用 “001abcd”,这个商业代码存储在我的主管理员数据库中,然后我告诉我的所有客户转到一个名为“example.com”的特定网址。

因此,如果他们输入网址,主页将看起来像slack.com,有一个输入框,并在硬编码值后称为example.com

所以现在我的客户端在输入框中放置了我创建它们的业务代码并存储在我的主数据库中。

将业务代码放入输入框后,将打开一个名为“001abcd.example.com”的新子域(我正在检查业务代码是否与我的主数据库匹配,如果匹配我正在创建动态子域)

所以如果一切都好,在创建子域客户端页面后会显示为需要注册的LOGIN屏幕,并且注册详细信息需要动态存在db

注意:我在创建业务时在主数据库表中获取客户端数据库,用户名,主机和密码。

如何使用sequelize mysql完成此操作?

如何根据客户端登录动态连接sequelize连接?

正如我之前所说的,我在我的数据库中有客户端dbname..etc,我正在尝试创建这样的连接:

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 在函数内部,所以我无法访问?全局。

所以我全局变量,但一个问题

我在函数内部有sequelizeClient变量,只有在url中输入我的域后才能执行,

但是sequelizeClient.sync()不在函数内部,所以当我启动节点server.js时它会抛出我的错误:

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

2 个答案:

答案 0 :(得分:0)

最后我尝试了这个并让它工作,但我不知道这是好方法,所以告诉我这是否是好方法?

我通过用户请求参数得到了确切的数据:

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));
};

答案 1 :(得分:0)

是的,经过大量搜索,我发现有三种数据库方法来构建SaaS产品,

  1. 每个租户的单独数据库
  2. 为所有租户分隔架构(表格)和通用的一个数据库
  3. 所有租户的共享表和一个数据库
  4. 最后我决定使用选项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. 在我的应用程序中,一个在线来了,他注册了,而注册我将商业代码存储到我的商业表中(商业表来自单独的数据库,这是一个超级主应用程序DB),所以我在postgres中找到业务代码并循环并制作动态模式

    4. 现在看看我的api,我正在根据req.user.code(来自登录会话)进行CRUD,我最终根据特定模式匹配显示数据,

    5. 所以最后我为每个客户端提供了清晰的单独模式

      谢谢!