Node.js中如何将MongoDB连接结果存入变量并供外部调用
如何在MongoClient.connect外部获取db实例并传递给routes模块
这个问题的核心是异步操作的执行时机:MongoClient.connect是异步方法,它的回调函数会在数据库连接成功后才触发,但你原来的代码里,app.listen和路由初始化是在connect还没完成时就执行了,这时候db实例还没生成,所以打印dbb会得到undefined。
下面是两种可行的解决方案:
方案1:使用async/await(推荐,代码更清晰)
把整个服务器启动逻辑放在async函数里,等待数据库连接完成后再初始化路由和启动服务:
const express = require('express'); const app = express(); const bodyParser = require('body-parser'); const MongoClient = require('mongodb').MongoClient; async function startServer() { try { // 等待数据库连接完成,获取客户端实例 const client = await MongoClient.connect( "mongodb://user:tpassword@ds137600.mlab.com:37600/tasksdb", { useNewUrlParser: true } ); const db = client.db(); console.log('已连接到数据库:', db.databaseName); // 把db实例传递给routes模块——需要修改routes的导出方式 const routes = require('./routes/routes')(db); // 配置中间件和路由 app.use(bodyParser.urlencoded({ extended: true })); app.use('/', routes); // 启动服务器 app.listen(3000, () => { console.log('Example app listening on port 3000!'); }); } catch (err) { console.error('数据库连接失败:', err); } } // 启动服务器 startServer();
对应的routes模块需要改成导出一个接受db参数的函数,这样就能在路由里使用数据库实例了:
// routes/routes.js const express = require('express'); const router = express.Router(); // 导出函数,接受db作为参数 module.exports = function(db) { // 示例路由:查询tasks集合的数据 router.get('/', (req, res) => { db.collection('tasks').find().toArray((err, results) => { if (err) { res.status(500).send('查询失败'); return; } res.send(results); }); }); // 返回配置好的路由实例 return router; };
方案2:在connect回调中执行所有依赖db的逻辑
如果不想用async/await,可以把路由初始化、服务器启动等所有依赖db的代码都放在connect的回调函数里,确保只有在数据库连接成功后才执行:
const express = require('express'); const app = express(); const bodyParser = require('body-parser'); const MongoClient = require('mongodb').MongoClient; MongoClient.connect( "mongodb://user:tpassword@ds137600.mlab.com:37600/tasksdb", { useNewUrlParser: true }, (err, client) => { if (err) { console.error('数据库连接失败:', err); return; } const db = client.db(); console.log('已连接到数据库:', db.databaseName); // 传递db给routes const routes = require('./routes/routes')(db); app.use(bodyParser.urlencoded({ extended: true })); app.use('/', routes); app.listen(3000, () => { console.log('Example app listening on port 3000!'); }); } );
routes模块的修改和方案1一样,都是导出接受db参数的函数。
为什么原来的代码不行?
你原来的代码里,const dbb = MongoClient.connect(...)其实拿到的是一个Promise对象,但在app.listen执行时,这个Promise还没有完成(数据库连接还没成功),所以打印dbb要么是Promise { <pending> },要么因为你用了回调写法没处理Promise,导致无法获取到实际的db实例。异步操作的结果必须在异步回调或Promise的then/catch中处理,不能直接在同步代码里使用。
内容的提问来源于stack exchange,提问作者Hamza Haddad
相关产品推荐
相关产品推荐

