【问题标题】:node js undefined mongodb connection节点js未定义的mongodb连接
【发布时间】:2025-11-25 19:35:01
【问题描述】:

我有 3 个文件

./custom/db.js 用于数据库连接到 mongodb

const mongodb= require('mongodb');
var mongoclient= require('mongodb').MongoClient;
var dburl1= 'mongodb://localhost:27017';
var _db;

    function dbconn(){
      var _db;
      async function books(){

        await mongoclient.connect(dburl1, {keepAlive: 30000, connectTimeoutMS: 30000, useUnifiedTopology: true }, (err, db)=>{
          dbo=  db.db('books');
          _db= dbo; 
         
        })
        return _db;
      }
      return {
        books: books, 
      }
    }
module.exports= dbconn();

./custom/ctrg.js从mongodb获取数据

async function books_by_ctrg(ctrg, limit, start) {
        console.log(ctrg);
    if(start == null) start=0;

        const dbo = await  db.books();

        // console.log(dbo);
        await dbo.collection('books1').find({}).skip(start).limit(limit).toArray((err, result)=>{if(err){console.log(err); return err;}else{data= result;}})
    
        return data;
};

./router/home.js 路由器文件(使用 Express 和 EJS)

router.get('/', async function (req, res) {
    var data =await books_data.get_book_ctrg('Latest_Books', 7, 0);
    var headerdata= {
            title: "", 
            des: "", 
            keywords: ""
            
    };
    // console.log(data);
    res.render('home.ejs', {data: data, headerdata: headerdata});
})

这些都在上面的文件以从主页的数据库中获取数据

问题

在首次加载时我得到了这个错误

node:6536) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'collection' of undefined
    at Object.books_by_ctrg [as get_book_ctrg] (C:\node\custom\ctrg.js:15:19)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async C:\node\routes\home.js:12:15
(node:6536) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:6536) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

在第二次加载时(这意味着数据库连接现在正在“没有文件更改,只是在浏览器中刷新”)

TypeError: C:\node\views\home.ejs:67
    65|         <div class="course-slider owl-carousel">
    66|
 >> 67|     <% data.forEach(book=>{ %>
    68|         <a href="<%= book.link %>">
    69|             <div class="course-item">
    70|                 <figure class="course-preview">

Cannot read property 'forEach' of undefined
    at eval (eval at compile (C:\node\node_modules\ejs\lib\ejs.js:662:12), <anonymous>:14:13)
    at home (C:\node\node_modules\ejs\lib\ejs.js:692:17)
    at tryHandleCache (C:\node\node_modules\ejs\lib\ejs.js:272:36)
    at View.exports.renderFile [as engine] (C:\node\node_modules\ejs\lib\ejs.js:489:10)
    at View.render (C:\node\node_modules\express\lib\view.js:135:8)
    at tryRender (C:\node\node_modules\express\lib\application.js:640:10)
    at Function.render (C:\node\node_modules\express\lib\application.js:592:3)
    at ServerResponse.render (C:\node\node_modules\express\lib\response.js:1012:7)
    at C:\node\routes\home.js:20:9
    at processTicksAndRejections (internal/process/task_queues.js:97:5)

这两次访问或刷新后(一切正常,没有错误,没有警告,一切都很完美)

【问题讨论】:

  • nodejs:v12.16.3,MongoDb:v5.x.x

标签: javascript node.js mongodb


【解决方案1】:

这个错误已经告诉了你很多。

TypeError:无法读取未定义的属性“集合”。

这意味着当您调用 await dbo.collection('books1') 时,dbo 变量是 undefined。这告诉我们db.books(); 不会返回您需要的Db 实例。所以问题出在./custom/db.js文件上。

在那个文件中有几个问题。

var _db; // <-- 1st definition of _db (it's not wrong, but just confusing).

function dbconn(){
  var _db; // <-- 2nd definition of _db (this should be the only definition).
  async function books(){

    // Because you use a callback, no promise is returned, therefor it will not await.
    // @see http://mongodb.github.io/node-mongodb-native/3.6/api/MongoClient.html#.connect
    await mongoclient.connect(dburl1, {keepAlive: 30000, connectTimeoutMS: 30000, useUnifiedTopology: true }, (err, db)=>{
      dbo=  db.db('books'); // <-- dbo is never defined
      _db= dbo; //
    })

    // _db will still be undefined because await didn't work.
    // This will cause the error.
    return _db;
  }
  
  return {
    books: books, 
  }
}

为什么返回undefined

所以罪魁祸首是因为callback parameter on mongoclient.connect, that function will not return a Promise。因此,await 关键字将无需等待,将直接继续到 return 关键字,返回一个 undefined 值。

为什么它第二次起作用了?

var _db 定义在函数的顶部。这是 db.db('books') 的结果将存储在其中的变量。该变量将位于闭包内,这意味着在返回 return { books: books } 后,它仍将存在于函数范围内。

现在第一次,_db 未定义并立即返回。但与此同时,mongoclient.connect() 将开始运行并更新闭包中的_db 变量。因此,如果您等待connect 函数完成的时间足够长,那么_db 变量现在将被更新并拥有一个Db 实例。第二次、第三次和每隔一次都会发生同样的事情,但不同的是_db 已经更新,不再是undefined

修改您的代码。

我查看了一些示例并注意到它们创建了一个 MongoClient 的实例,其中包含 DB 的 URL 和连接设置。

请参见下面的示例。它首先创建一个实例,然后使用该实例连接并返回您需要的Db

const { MongoClient } = require("mongodb");
const dburl1 = "mongodb://localhost:27017";

function dbconn() {
  const mongoclient = new MongoClient(dburl1, {
    connectTimeoutMS: 30000,
    useUnifiedTopology: true
  });

  async function books() {
    try {
      await mongoclient.connect();
      return mongoclient.db("books");
    } catch(error) {
      console.error(error);
    } finally {
      await client.close();
    }
  }

  return {
    books
  };
}

module.exports = dbconn();

【讨论】:

  • 也许这不是问题 当我刷新页面时,相同的脚本运行良好。第一次页面加载的 Dbo 未定义返回不是第二次
  • 嗯,第一次_db 将是未定义的,但似乎mongoclient.connect 在返回后仍会更新全局_db 变量。这意味着第二次返回 _db 时,它将不再是未定义的并且具有 Db 实例。这个答案将解决这个问题。
  • 你能解释一下为什么它在第二次加载或刷新时能正常工作吗?非常感谢您指出我大致相同,我已经修复了我的 ctrg.js 文件,现在一切都很好。