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

NodeJS中实现MongoDB单例数据库对象的问题

实现MongoDB单例连接的完整方案

我帮你把这个MongoDB单例连接的方案补全并梳理清楚,刚好适配你的Express+Socket.io项目场景。首先先把你的mongoUtil.js补全成可运行的版本,核心就是维护一个全局的数据库实例,初始化时连接一次,后续所有业务逻辑复用这个连接:

var MongoClient = require('mongodb').MongoClient;
var _db;

module.exports = {
  // 连接数据库并初始化全局实例
  connectToServer: async function(callback) {
    try {
      // 这里替换成你的MongoDB连接字符串,建议存在环境变量里
      const client = await MongoClient.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/your-project-db');
      _db = client.db(); // 绑定数据库实例到全局变量
      console.log('✅ MongoDB连接成功');
      callback(null, _db);
    } catch (err) {
      console.error('❌ MongoDB连接失败:', err);
      callback(err);
    }
  },

  // 获取已初始化的数据库实例
  getDb: function() {
    return _db;
  }
};

接下来是项目入口文件(比如app.js)的配置,一定要等数据库连接成功后再启动服务器和加载业务逻辑,避免出现调用getDb()返回null的情况:

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const mongoUtil = require('./mongoUtil');

const app = express();
const server = http.createServer(app);
const io = socketIo(server);

// 先完成数据库连接,再启动服务
mongoUtil.connectToServer(function(err, db) {
  if (err) {
    console.error('数据库连接失败,程序退出');
    process.exit(1);
  }

  // 启动HTTP服务器
  const PORT = process.env.PORT || 3000;
  server.listen(PORT, () => {
    console.log(`🚀 服务器运行在端口 ${PORT}`);
  });

  // 加载Express路由和Socket.io处理逻辑
  require('./routes/userRoutes')(app);
  require('./socket/chatHandlers')(io);
});

然后看业务场景里的使用方式:

在Express路由中使用

比如routes/userRoutes.js,直接调用getDb()获取实例操作集合:

const mongoUtil = require('../mongoUtil');

module.exports = function(app) {
  app.get('/api/users', async (req, res) => {
    try {
      const db = mongoUtil.getDb();
      const users = await db.collection('users').find({}).toArray();
      res.status(200).json(users);
    } catch (err) {
      res.status(500).json({ error: '获取用户列表失败', message: err.message });
    }
  });
};

在Socket.io中使用

比如socket/chatHandlers.js,在客户端连接后的事件里复用数据库连接:

const mongoUtil = require('../mongoUtil');

module.exports = function(io) {
  io.on('connection', (socket) => {
    console.log('新客户端连接:', socket.id);

    // 监听客户端获取消息的请求
    socket.on('fetch-chat-messages', async () => {
      try {
        const db = mongoUtil.getDb();
        const messages = await db.collection('chat_messages')
          .find({})
          .sort({ created_at: -1 })
          .limit(20)
          .toArray();
        socket.emit('chat-messages', messages.reverse());
      } catch (err) {
        socket.emit('error', '获取消息失败');
      }
    });

    socket.on('disconnect', () => {
      console.log('客户端断开连接:', socket.id);
    });
  });
};

最后给你几个关键提醒:

  • 连接字符串建议用环境变量管理,本地开发可以用.env文件配合dotenv包加载,线上直接设置服务器环境变量,避免硬编码敏感信息。
  • 不要在每个请求或Socket事件里新建连接,复用单例才能最大化数据库连接池的效率,避免资源浪费。
  • 如果你的项目用ES模块(import/export),只需要把require改成import,结构逻辑完全一致。

内容的提问来源于stack exchange,提问作者Willem van der Veen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:19:43