MongoDB Atlas连接Node.js时遇'dbItem is not defined'错误求助
解决MongoDB Atlas连接后
ReferenceError: dbItem is not defined错误 问题描述
已创建MongoDB Atlas数据库,Node.js成功连接,但运行服务器时出现错误:ReferenceError: dbItem is not defined,dbItem是定义的集合常量。相关代码如下:
const express = require("express"); const bodyParser = require("body-parser"); const { MongoClient } = require("mongodb"); const app = express(); app.set('view engine', 'ejs'); app.use(bodyParser.urlencoded({extended: true})); app.use(express.static("public")); const uri = "mongodb+srv://username:1234321@cluster0.8imjcky.mongodb.net/?retryWrites=true&w=majority"; const client = new MongoClient(uri); async function run() { try { const todolistDB = client.db("todolistDB"); const dbItem = todolistDB.collection("Item"); const defaultItems = [ { item1: "welcome to your todolist" }, { item2: "add new Item"}, { item3: "delete item"} ]; const result = await dbItem.insertMany(defaultItems); console.log(`${result.insertedCount} documents were inserted`); } finally { await client.close(); } } run().catch(console.dir); app.get("/", function(req, res) { //const dbItem = app.locals.collection; dbItem.find({}, function(err, foundItems){ res.render("list", {listTitle: "Today", newListItems: foundItems}); }); });
应用已成功连接Atlas,且dbItem集合已在Atlas中创建,曾尝试在app.get函数前使用app.locals.collections = dbItem,但问题仍未解决。
问题根源
- 作用域问题:
dbItem是run函数内部的局部变量,app.get的回调函数处于外部作用域,无法访问该变量。 - 连接关闭问题:
run函数执行完毕后调用了client.close(),导致后续请求时MongoDB连接已关闭,即使能拿到dbItem也无法正常操作数据库。 - 错误的
app.locals赋值:之前直接在run函数外部给app.locals赋值,此时dbItem还未定义,赋值的是undefined,自然无法在路由中使用。
修正方案
完整修正代码
const express = require("express"); const bodyParser = require("body-parser"); const { MongoClient } = require("mongodb"); const app = express(); app.set('view engine', 'ejs'); app.use(bodyParser.urlencoded({extended: true})); app.use(express.static("public")); const uri = "mongodb+srv://username:1234321@cluster0.8imjcky.mongodb.net/?retryWrites=true&w=majority"; const client = new MongoClient(uri); async function run() { try { // 显式建立MongoDB连接 await client.connect(); const todolistDB = client.db("todolistDB"); const dbItem = todolistDB.collection("Item"); // 将集合引用挂载到app.locals,供路由访问 app.locals.dbItem = dbItem; const defaultItems = [ { item: "welcome to your todolist" }, { item: "add new Item"}, { item: "delete item"} ]; // 检查集合是否为空,避免重复插入默认数据 const itemCount = await dbItem.countDocuments(); if (itemCount === 0) { const result = await dbItem.insertMany(defaultItems); console.log(`${result.insertedCount} documents were inserted`); } // 数据库连接成功后再启动服务 app.listen(3000, function() { console.log("Server started on port 3000"); }); } catch(err) { // 捕获连接或数据库操作错误 console.error("Database connection error:", err); } // 不在这里关闭client,保持长连接供服务持续使用 } run().catch(console.dir); app.get("/", async function(req, res) { try { // 从app.locals获取集合引用 const dbItem = req.app.locals.dbItem; // 使用async/await处理异步查询,替代回调写法 const foundItems = await dbItem.find({}).toArray(); res.render("list", {listTitle: "Today", newListItems: foundItems}); } catch(err) { console.error("Fetch items error:", err); res.status(500).send("Failed to load todolist items"); } });
关键修改说明
- 保持数据库长连接:移除
finally块中的client.close(),Express服务需要持续的数据库连接来处理后续请求。 - 正确挂载集合引用:在
run函数内部获取到dbItem后,再将其挂载到app.locals,确保路由能访问到有效的集合引用。 - 异步操作优化:路由回调改为
async函数,使用await处理MongoDB查询,这是MongoDB v4+推荐的写法,比回调更易维护。 - 避免重复插入:添加集合文档数量检查,只有当集合为空时才插入默认数据,防止每次服务启动都重复添加相同内容。
- 延迟启动服务:将
app.listen放在run函数内部,确保数据库连接成功后再接收请求,避免请求时数据库尚未准备好。
内容的提问来源于stack exchange,提问作者Oswald
相关产品推荐
相关产品推荐

