You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js与Mongoose中动态MongoDB分支数据库连接实现求助

多分支动态Mongoose数据库连接实现方案

核心实现思路

  • 保留全局主数据库连接:专门用于存储分支信息、用户权限数据(对应你的adminBranches库),启动时建立并全程复用。
  • 维护分支连接缓存池:用对象缓存已创建的分支数据库连接,避免重复建立连接消耗资源。
  • 会话绑定分支连接:用户选择分支后,将分支标识(如数据库名/分支ID)存入Session,后续请求从Session读取标识,再从缓存池获取对应连接。
  • 动态绑定模型:基于分支的Mongoose连接实例创建数据模型,确保操作的是当前分支的数据库。

代码实现示例

1. 重构主数据库连接(全局连接)

修改原有的全局连接逻辑,专门连接adminBranches主库:

// db/connectMain.js
const mongoose = require('mongoose');
const config = require('config');

let mainDbConnection;

async function connectMainDB() {
  try {
    mainDbConnection = await mongoose.createConnection(config.get('mongoURI'), {
      useNewUrlParser: true,
      useUnifiedTopology: true
    });
    console.log('主数据库adminBranches连接成功');
    return mainDbConnection;
  } catch (err) {
    console.error('主数据库连接失败:', err);
    process.exit(1);
  }
}

// 定义分支信息模型(存储在主库)
const Branch = mainDbConnection.model('Branch', new mongoose.Schema({
  branchId: { type: String, unique: true },
  dbName: { type: String, required: true },
  dbUri: { type: String, required: true },
  allowedUsers: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }]
}));

module.exports = { connectMainDB, mainDbConnection, Branch };

替换入口文件中的全局连接调用:

// 原入口文件修改
const { connectMainDB } = require('./db/connectMain');

// ...其他配置代码(保留你原有的PORT、SESSION_SECRET等配置)

//-----------------------------Middleware Start------------------//
connectMainDB();

2. 分支连接管理模块

创建db/branchDbManager.js,负责缓存和获取分支连接:

const mongoose = require('mongoose');

// 缓存已建立的分支连接,key为分支数据库名
const branchConnections = {};

/**
 * 获取分支数据库连接
 * @param {string} dbUri - 分支数据库的连接URI
 * @param {string} dbName - 分支数据库名称
 * @returns {mongoose.Connection}
 */
async function getBranchConnection(dbUri, dbName) {
  // 如果连接已存在且可用,直接返回
  if (branchConnections[dbName] && branchConnections[dbName].readyState === 1) {
    return branchConnections[dbName];
  }

  // 新建连接
  try {
    const connection = await mongoose.createConnection(dbUri, {
      useNewUrlParser: true,
      useUnifiedTopology: true
    });
    branchConnections[dbName] = connection;
    console.log(`分支数据库${dbName}连接成功`);
    return connection;
  } catch (err) {
    console.error(`分支数据库${dbName}连接失败:`, err);
    throw err;
  }
}

/**
 * 关闭指定分支连接(可选,用于资源清理)
 * @param {string} dbName
 */
async function closeBranchConnection(dbName) {
  if (branchConnections[dbName]) {
    await branchConnections[dbName].close();
    delete branchConnections[dbName];
    console.log(`分支数据库${dbName}连接已关闭`);
  }
}

module.exports = { getBranchConnection, closeBranchConnection, branchConnections };

3. 登录与分支选择接口

// routes/auth.js
const express = require('express');
const router = express.Router();
const { Branch } = require('../db/connectMain');
const { getBranchConnection } = require('../db/branchDbManager');

// 登录接口:验证用户并返回可访问分支
router.post('/login', async (req, res) => {
  // 此处替换为你的用户验证逻辑,获取当前登录用户
  const user = await verifyUser(req.body.username, req.body.password);
  
  // 查询用户可访问的分支列表
  const accessibleBranches = await Branch.find(
    { allowedUsers: user._id },
    'branchId dbName'
  );
  
  // 将用户信息和分支列表存入Session
  req.session.user = user;
  req.session.accessibleBranches = accessibleBranches;
  
  res.json({ success: true, branches: accessibleBranches });
});

// 选择分支接口:建立分支连接并绑定到Session
router.post('/select-branch', async (req, res) => {
  const { branchId } = req.body;
  const user = req.session.user;
  
  if (!user) return res.status(401).json({ message: '未登录' });
  
  // 验证用户是否有该分支访问权限
  const branch = await Branch.findOne({
    branchId,
    allowedUsers: user._id
  });
  if (!branch) return res.status(403).json({ message: '无该分支访问权限' });
  
  // 获取或创建分支连接
  await getBranchConnection(branch.dbUri, branch.dbName);
  
  // 将当前分支信息存入Session
  req.session.currentBranch = {
    branchId: branch.branchId,
    dbName: branch.dbName
  };
  
  res.json({ success: true, branch: branch.branchId });
});

module.exports = router;

4. 分支连接复用中间件

创建中间件,在请求中注入当前分支的连接和模型:

// middleware/branchDbMiddleware.js
const { branchConnections } = require('../db/branchDbManager');
const mongoose = require('mongoose');

// 动态创建分支库的模型(所有分支库模型结构一致)
function createBranchModels(connection) {
  // 示例:创建订单模型,根据你的业务需求调整
  const Order = connection.model('Order', new mongoose.Schema({
    orderNo: String,
    amount: Number,
    createdAt: { type: Date, default: Date.now }
  }));
  
  return { Order };
}

module.exports = (req, res, next) => {
  const currentBranch = req.session.currentBranch;
  
  // 用户未选择分支时返回提示
  if (!currentBranch) {
    return res.status(400).json({ message: '请先选择操作分支' });
  }
  
  // 从缓存获取分支连接
  const conn = branchConnections[currentBranch.dbName];
  if (!conn || conn.readyState !== 1) {
    return res.status(500).json({ message: '分支连接已失效,请重新选择分支' });
  }
  
  // 将连接和模型注入req对象,供后续路由使用
  req.branchDb = conn;
  req.branchModels = createBranchModels(conn);
  
  next();
};

5. 使用分支连接的业务路由

// routes/order.js
const express = require('express');
const router = express.Router();
const branchDbMiddleware = require('../middleware/branchDbMiddleware');

// 应用分支连接中间件,确保后续路由能获取到分支连接
router.use(branchDbMiddleware);

// 查询当前分支的订单列表
router.get('/orders', async (req, res) => {
  try {
    const orders = await req.branchModels.Order.find().sort({ createdAt: -1 });
    res.json({ success: true, data: orders });
  } catch (err) {
    res.status(500).json({ message: '查询失败', error: err.message });
  }
});

module.exports = router;

内容的提问来源于stack exchange,提问作者Mediator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 05:13:36