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
相关产品推荐
相关产品推荐

