NodeJS连接MongoDB无法创建集合 createCollection未定义报错
问题描述
8个月前可正常运行的相同代码配置突然失效,访问/createDatabase接口时抛出类型错误,排查发现数据库连接未成功建立,无法定位根因,需要更合理的实现方案。
- 错误核心表现:全局存储的数据库连接对象
con为undefined,调用createCollection方法时触发类型错误 - 部署方式:基于Docker Compose部署
原有服务端代码
'use strict' const express = require('express'); const MongoClient = require('mongodb').MongoClient; const url = 'mongodb://toor:root@mongodbdatabase:27017/' const app = express(); const PORT = 8080; const HOST = '0.0.0.0'; let con; MongoClient.connect(url, (err, db) => { con = db.db("mongodbdatabase"); }) app.use('/', express.static('public')); app.get('/createDatabase', (req, res) => { con.createCollection("HiveDB", function(err, result) { if (err) throw err; console.log("Collection Created") }) res.send(); }) console.log(`Listening on port ${PORT}`) app.listen(PORT, HOST);
报错信息
TypeError: Cannot read properties of undefined (reading 'createCollection') at /usr/src/app/server.js:28:9 at Layer.handle [as handle_request] (/usr/src/app/node_modules/express/lib/router/layer.js:95:5) at next (/usr/src/app/node_modules/express/lib/router/route.js:144:13) at Route.dispatch (/usr/src/app/node_modules/express/lib/router/route.js:114:3) at Layer.handle [as handle_request] (/usr/src/app/node_modules/express/lib/router/layer.js:95:5) at /usr/src/app/node_modules/express/lib/router/index.js:284:15 at Function.process_params (/usr/src/app/node_modules/express/lib/router/index.js:346:12) at next (/usr/src/app/node_modules/express/lib/router/index.js:280:10) at SendStream.error (/usr/src/app/node_modules/serve-static/index.js:121:7) at SendStream.emit (node:events:537:28)
原有部署配置
Dockerfile
FROM node:latest EXPOSE 8080 WORKDIR /usr/src/app RUN npm install express --save RUN npm install mongodb --save RUN npm install -g loadtest --save COPY server.js /usr/src/app/server.js COPY /public /usr/src/app/public CMD ["node", "server.js"]
docker-compose.yml
version: '3' services: mainserver: build: ./main depends_on: - mongodbdatabase container_name: mainServer ports: - "83:8080" mongodbdatabase: image: mongo container_name: monDataBase ports: - 27017:27017 environment: MONGO_INITDB_ROOT_USERNAME: toor MONGO_INITDB_ROOT_PASSWORD: root
问题根因
- 异步时序错误:
MongoClient.connect是异步非阻塞操作,原代码没有等待连接完成就启动了HTTP服务,请求到达接口时连接回调尚未执行,con变量还未赋值,自然是undefined。 - 无错误处理逻辑:连接回调完全没有捕获连接错误,不管是Mongo未就绪、认证失败还是网络不通,连接失败时没有任何日志输出,直接导致后续数据库实例对象为空。
- Docker依赖逻辑不生效:
depends_on配置仅等待Mongo容器启动完成,不会等待Mongo数据库服务初始化完毕、可接收连接,Node服务启动时大概率Mongo还在初始化,连接直接失败。 - 版本漂移问题:Dockerfile使用
node:latest基础镜像,npm安装依赖也未锁定版本,8个月间MongoDB Node驱动从3.x迭代到4.x+版本,连接默认超时、认证逻辑均有调整,进一步放大了时序问题。 - 连接串配置缺失:Mongo root账号默认在admin库下创建,原连接串未指定
authSource=admin参数,驱动会默认在业务库下查找用户,直接导致认证失败。
修复实现
1. 调整服务端代码逻辑
把HTTP服务启动逻辑放到Mongo连接成功的回调中,补充完整错误处理,连接失败直接打印日志退出进程方便排查:
'use strict' const express = require('express'); const { MongoClient } = require('mongodb'); // 补充authSource=admin指定认证库,直接写入要连接的业务库 const url = 'mongodb://toor:root@mongodbdatabase:27017/mongodbdatabase?authSource=admin'; const app = express(); const PORT = 8080; const HOST = '0.0.0.0'; const client = new MongoClient(url); app.use('/', express.static('public')); app.get('/createDatabase', async (req, res) => { try { const db = client.db('mongodbdatabase'); await db.createCollection("HiveDB"); console.log("Collection Created"); res.send('Collection created successfully'); } catch (err) { console.error('Create collection failed:', err); res.status(500).send('Internal server error'); } }) // 先建立数据库连接,确认连通后再启动HTTP服务 async function startServer() { try { await client.connect(); // 发送ping命令验证连接可用性 await client.db().command({ ping: 1 }); console.log("Connected to MongoDB successfully"); app.listen(PORT, HOST, () => { console.log(`Listening on port ${PORT}`); }); } catch (err) { console.error('Failed to connect to MongoDB:', err); process.exit(1); } } startServer();
2. 优化Docker配置
锁定基础镜像和依赖版本避免无感知升级,给Mongo服务增加健康检查,确认服务就绪后再启动Node服务:
修改后的Dockerfile:
# 锁定Node大版本,禁止使用latest FROM node:18-bullseye EXPOSE 8080 WORKDIR /usr/src/app # 优先复制依赖配置文件,复用Docker构建缓存 COPY package*.json ./ # 使用npm ci按锁文件安装依赖,避免版本漂移 RUN npm ci --omit=dev RUN npm install -g loadtest COPY server.js /usr/src/app/server.js COPY /public /usr/src/app/public CMD ["node", "server.js"]
修改后的docker-compose.yml:
version: '3' services: mainserver: build: ./main depends_on: mongodbdatabase: # 等待Mongo健康检查通过后再启动 condition: service_healthy container_name: mainServer ports: - "83:8080" # 异常退出自动重启 restart: on-failure mongodbdatabase: # 锁定Mongo大版本 image: mongo:6 container_name: monDataBase ports: - 27017:27017 environment: MONGO_INITDB_ROOT_USERNAME: toor MONGO_INITDB_ROOT_PASSWORD: root # 配置健康检查,确认Mongo可正常响应 healthcheck: test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet interval: 5s timeout: 5s retries: 10
内容的提问来源于stack exchange,提问作者ConnerWithAnE
相关产品推荐
相关产品推荐

