使用NodeJS连接多个数据库并续集
#node #postgres #database #sequelize

我知道你为什么在这里。您已经达到了希望使用续集库与多个数据库进行交互的地步。但是,您最近注意到续集文档提到

如果您是从一个过程中连接到数据库的,则应仅创建一个续集实例。续集将在初始化时设置一个连接池。

因此,这意味着我们必须为每个数据库生成一个新实例,我们打算建立连接。您的目标是规避创建大量实例的需求,这使您寻求帮助。此外,您对写有关这个关键主题的工程师的短缺感到好奇。我也分享你的奇迹。

好消息正在等待您!您来到了理想的位置。下面,我提供了有关如何连接多个数据库而无需创建多个实例的全面,分步的指南。

我想从头开始,但是一位前同事已经在Getting Started with Sequelize and Postgres.上做得很好。如果您尚未创建node.js并续集项目,我建议您单击链接以获取详细说明。但是,如果您已经在研究一个,请随时无视链接。

让我们假设您已经使用了一个名为Customer的Postgres数据库,并且您想添加这4个Postgres(由sequelize支持的任何数据库)数据库到您的Nodejs应用程序:

  • 钱包
  • auth
  • 商人
  • 拉恩斯

步骤1:

创建一个.env文件并填充它,如下所示:

PORT=
API_VERSION=

DB_USERNAME=
DB_PASSWORD=
DB_NAME=
DB_HOST=
DB_PORT=

DB_CUSTOMER_URL=
DB_CUSTOMER_USERNAME=
DB_CUSTOMER_PASSWORD=
DB_CUSTOMER_NAME=
DB_CUSTOMER_HOST=

DB_WALLET_URL=
DB_WALLET_USERNAME=
DB_WALLET_PASSWORD=
DB_WALLET_NAME=
DB_WALLET_HOST=

DB_ROLE_URL=
DB_ROLE_USERNAME=
DB_ROLE_PASSWORD=
DB_ROLE_NAME=
DB_ROLE_HOST=

DB_MERCHANT_URL=
DB_MERCHANT_USERNAME=
DB_MERCHANT_PASSWORD=
DB_MERCHANT_NAME=
DB_MERCHANT_HOST=

DB_AUTH_URL=
DB_AUTH_USERNAME=
DB_AUTH_PASSWORD=
DB_AUTH_NAME=
DB_AUTH_HOST=

第2步:

在配置目录中,修改您的config.ts(如果不使用Typescript,则config.js):

import config from "./index";

const { secrets, dbVariables } = config();

module.exports = {
  development: {
    username: secrets.username,
    password: secrets.password,
    database: secrets.name,
    host: secrets.host,
    port: secrets.port,
    dialect: "postgres",
    dialectOptions: {
      bigNumberStrings: true,
    },
    databases: {
      Customer: {
        username: dbVariables.dbCustomerUsername,
        password: dbVariables.dbCustomerPassword,
        database: dbVariables.dbCustomerName,
        host: dbVariables.dbCustomerHost,
        port: 5432,
        dialect: "postgres",
        dialectOptions: {
          bigNumberStrings: true,
        },
      },
      Auth: {
        username: dbVariables.dbAuthUsername,
        password: dbVariables.dbAuthPassword,
        database: dbVariables.dbAuthName,
        host: dbVariables.dbAuthHost,
        port: 5432,
        dialect: "postgres",
        dialectOptions: {
          bigNumberStrings: true,
        },
      },
      Wallet: {
        username: dbVariables.dbWalletUsername,
        password: dbVariables.dbWalletPassword,
        database: dbVariables.dbWalletName,
        host: dbVariables.dbWalletHost,
        port: 5432,
        dialect: "postgres",
        dialectOptions: {
          bigNumberStrings: true,
        },
      },

      Merchant: {
        username: dbVariables.dbMerchantUsername,
        password: dbVariables.dbMerchantPassword,
        database: dbVariables.dbMerchantName,
        host: dbVariables.dbMerchantHost,
        port: 5432,
        dialect: "postgres",
        dialectOptions: {
          bigNumberStrings: true,
        },
      },
      Role: {
        username: dbVariables.dbRoleUsername,
        password: dbVariables.dbRolePassword,
        database: dbVariables.dbRoleName,
        host: dbVariables.dbRoleHost,
        port: 5432,
        dialect: "postgres",
        dialectOptions: {
          bigNumberStrings: true,
        },
      },
    },
  },
};

在这里,我们成功地宣布了另外4个数据库,并具有其证书。现在,您必须注意到我在此文件的开头导入了一个索引文件。这不是强制性的。我总是喜欢为我的秘密键提供一个单独的文件。只要坚持下去,我们将尽快创建该索引文件。现在说到保持代码清洁,让我们创建一个辅助文件,该文件将通过循环循环来读取和声明我们所有的DB环境变量。

步骤3:

在您的帮助者目录中,创建一个dbConfig.ts文件并输入以下代码行:

export const fetchAllDbConfig = () => {
  const DBs = {
    CUSTOMER: "Customer",
    WALLET: "Wallet",
    ROLE: "Role",
    MERCHANT: "Merchant",
    AUTH: "Auth",
  };

  const dbVariables = {};
  for (let [key, value] of Object.entries(DBs)) {
    dbVariables[`db${value}URL`] = process.env[`DB_${key}_URL`] || "";
    dbVariables[`db${value}Name`] = process.env[`DB_${key}_NAME`] || "";
    dbVariables[`db${value}Host`] = process.env[`DB_${key}_HOST`] || "";
    dbVariables[`db${value}Password`] = process.env[`DB_${key}_PASSWORD`] || "";
    dbVariables[`db${value}Username`] = process.env[`DB_${key}_USERNAME`] || "";
  }
  return dbVariables;
};

步骤4:

现在让我们看一下我们之前导入的此索引文件。
回到创建我们在config.ts文件中导入的索引文件。在同一config Directory中创建一个index.ts文件并向其添加以下行。

import dotenv from "dotenv";
import path from "path";
import { fetchAllDbConfig } from "../helpers/dbConfig";

// describes a secrets object
type Secrets = Readonly<{
  env: string;
  version: string;
  port: string;
  secrets: {
    name: string;
    host: string;
    port: number;
    username: string;
    password: string;
  };
  dbVariables: {
    dbCustomerURL: string;
    dbCustomerName: string;
    dbCustomerHost: string;
    dbCustomerPassword: string;
    dbCustomerUsername: string;

    dbWalletURL: string;
    dbWalletName: string;
    dbWalletHost: string;
    dbWalletPassword: string;
    dbWalletUsername: string;

    dbRoleURL: string;
    dbRoleName: string;
    dbRoleHost: string;
    dbRolePassword: string;
    dbRoleUsername: string;

    dbAuthURL: string;
    dbAuthName: string;
    dbAuthHost: string;
    dbAuthPassword: string;
    dbAuthUsername: string;

    dbMerchantURL: string;
    dbMerchantName: string;
    dbMerchantHost: string;
    dbMerchantPassword: string;
    dbMerchantUsername: string;
  };
}>;

const env = process.env.NODE_ENV || "development";
let envfile: string;

switch (env) {
  case "production":
    envfile = ".env";
    break;
  case "test":
    envfile = ".env.test";
    break;
  case "development":
  default:
    envfile = ".env.local";
    break;
}

const envpath: string = path.join(__dirname, "../..", envfile);
let cache: Secrets | any;

export default function config() {
  if (!cache) {
    dotenv.config({ path: envpath });
    cache = Object.freeze({
      env,
      version: process.env.API_VERSION || "v1",
      port: process.env.PORT || "3300",
      secrets: {
        name: process.env.DB_NAME || "",
        host: process.env.DB_HOST || "",
        port: +(process.env.DB_PORT || "") || 25,
        username: process.env.DB_USERNAME || "",
        password: process.env.DB_PASSWORD || "",
      },
      dbVariables: fetchAllDbConfig(),
    });
  }
  return cache;
}

在这里,我们以更干净的格式声明了我们的变量。另外,请注意我们如何从之前创建的助手/DBConfig导入fetchAllDbConfig

步骤5:

仔细编辑models/index.js文件如下:

"use strict";

const fs = require("fs");
const path = require("path");
const Sequelize = require("sequelize");
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || "development";
const config = require(path.resolve("build/config", "config.js"))[env];

const db = {};
const databases = Object.keys(config.databases);

for (let i = 0; i < databases.length; ++i) {
  let database = databases[i];
  let dbPath = config.databases[database];
  if (config.use_env_variable) {
    db[database] = new Sequelize(process.env[config.use_env_variable], config);
  } else {
    db[database] = new Sequelize(
      dbPath.database,
      dbPath.username,
      dbPath.password,
      dbPath
    );
  }
}

for (let i = 0; i < databases.length; ++i) {
  let database = databases[i].toLowerCase();
  fs.readdirSync(`${__dirname}/${database}`)
    .filter((file) => {
      return (
        file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js"
      );
    })
    .forEach((file) => {
      const model = require(path.join(`${__dirname}/${database}`, file))(
        db[databases[i]],
        Sequelize.DataTypes
      );

      db[model.name] = model;
    });
}

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

module.exports = db;

“ db”对象当前保留了我们config.js文件中所有数据库的连接信息。但是,它缺乏有关数据库中模型的详细信息,从而导致SQL查询不正确。为了纠正这一点,我们必须从模型文件中读取模型信息并将其集成到“ db”对象中。

请在我们进行时要注意。为了实现这一目标,我们必须修改如下所示的文件夹结构:

步骤6:

重组您的文件夹树以如下所示。

multiple databases with Sequelize and nodejs folder structure

步骤7:

为每个数据库创建类似于我们的.SequeLizerc文件的新续集选项文件。因此,让我们在包装的目录中创建这两个文件。JSON文件:

  • .Seperize-Customer

在每个文件中,我们可以定义我们的配置,型号,迁移和播种机的目录。对于所有5个文件,请记住更改名称。以下是.sequelize-customer文件的外观。

const path = require("path");

module.exports = {
  config: path.resolve("build/config", "config.js"),
  "models-path": path.resolve("src/db/models"),
  "seeders-path": path.resolve("src/db/models/customer/seeders"),
  "migrations-path": path.resolve("src/db/models/customer/migrations"),
};

步骤8:

在您的软件包中。

{
    "customer:migrate": "sequelize --options-path ./.sequelize-customer --env development db:migrate",
    "customer:seed": "sequelize --options-path ./.sequelize-customer --env development db:seed:all",

    "wallet:migrate": "sequelize --options-path ./.sequelize-wallet --env development db:migrate",
    "wallet:seed": "sequelize --options-path ./.sequelize-wallet --env development db:seed:all",

    "merchant:migrate": "sequelize --options-path ./.sequelize-merchant --env development db:migrate",
    "merchant:seed": "sequelize --options-path ./.sequelize-merchant --env development db:seed:all",

    "role:migrate": "sequelize --options-path ./.sequelize-role --env development db:migrate",
    "role:seed": "sequelize --options-path ./.sequelize-role --env development db:seed:all",

    "auth:migrate": "sequelize --options-path ./.sequelize-auth --env development db:migrate",
    "auth:seed": "sequelize --options-path ./.sequelize-auth --env development db:seed:all",
}

从GitHub回购下载

您可以从github repo

克隆此模板

步骤9:

恭喜。你做到了。您现在可以从一个实例访问所有五个不同的数据库。

请不要忘记留下类似的评论。

参考: