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

Node.js/Express:如何将Mongo数据库连接共享给其他模块?

解决Node.js中MongoDB连接共享与状态检测问题

当然可以共享单个MongoDB连接实例,MongoClient本身就设计为可复用的单例对象,驱动会自动维护连接池,直到你主动调用client.close()才会断开连接。你的代码问题出在异步函数中动态修改模块导出,导致其他模块导入时无法获取到已初始化的client。

问题根源

模块的module.exports是同步加载的,当其他模块导入你的数据库模块时,connect()异步函数还没执行完,此时导出的是默认的空对象,自然会出现undefined或is not a function错误。

正确的连接共享实现

方案1:用Promise封装连接过程(通用方案)

创建独立的db.js模块,通过Promise确保获取到的是已连接的client:

const { MongoClient } = require('mongodb');
const uri = '你的MongoDB连接字符串';

const client = new MongoClient(uri, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

// 缓存连接Promise,避免重复发起连接请求
let connectPromise;

// 获取已连接的client
async function getClient() {
  if (!connectPromise) {
    connectPromise = client.connect()
      .then(() => {
        console.log('MongoDB连接成功');
        return client;
      })
      .catch(err => {
        console.error('MongoDB连接失败:', err);
        // 连接失败后重置Promise,允许后续重试
        connectPromise = null;
        throw err;
      });
  }
  return connectPromise;
}

// 检测连接是否处于打开状态
function isConnected() {
  // 检查topology是否存在且已连接
  return client.topology && client.topology.isConnected();
}

module.exports = { getClient, isConnected };

其他模块使用方式

const { getClient, isConnected } = require('./db');

async function insertProductionLog(doc) {
  // 可选:提前检测连接状态
  if (!isConnected()) {
    console.log('连接未就绪,正在初始化连接...');
  }

  // 确保获取到已连接的client
  const client = await getClient();
  await client.db('syslogs').collection('production').insertOne(doc);
}

方案2:Express项目中结合app.locals

如果你用Express,可以在服务器启动前完成连接,再将client挂载到app.locals:

// app.js
const express = require('express');
const { getClient } = require('./db');
const app = express();

async function startServer() {
  // 先完成MongoDB连接
  const mongoClient = await getClient();
  // 将client挂载到app.locals,供路由使用
  app.locals.mongoClient = mongoClient;

  // 配置中间件和路由
  app.use(express.json());

  app.post('/logs/production', async (req, res) => {
    try {
      await req.app.locals.mongoClient.db('syslogs').collection('production').insertOne(req.body);
      res.status(200).send('日志插入成功');
    } catch (err) {
      res.status(500).send(`插入失败: ${err.message}`);
    }
  });

  app.listen(3000, () => {
    console.log('服务器运行在http://localhost:3000');
  });
}

// 启动服务器
startServer().catch(err => console.error('服务器启动失败:', err));

关键注意事项

  • 始终复用同一个MongoClient实例,不要每次操作都创建新实例,否则会耗尽连接池资源
  • 不要在异步函数中修改module.exports,模块导出是同步机制,异步修改无法被其他模块捕获
  • 连接状态检测依赖client.topology.isConnected(),这是MongoDB Node驱动提供的官方方法
  • 应用关闭时,记得调用client.close()释放连接:
// 捕获进程退出信号,关闭连接
process.on('SIGINT', async () => {
  await client.close();
  console.log('MongoDB连接已关闭');
  process.exit(0);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 15:05:26