“拓扑被破坏".将MongoDB与本机驱动程序和Express.js一起使用时 [英] "Topology was destroyed" when using MongoDB with native driver and Express.js

查看:87
本文介绍了“拓扑被破坏".将MongoDB与本机驱动程序和Express.js一起使用时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经实现了一个简单的应用程序,可以从MongoDB中获取数据

I have implemented simple application that fetches data from MongoDB

const express = require('express')
const app = express()
const port = 3000

const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');

const dbConnectionURL = 'mongodb://localhost:27017';
const dbName = 'todo';
const dbClient = new MongoClient(dbConnectionURL);

function findTodos(db, callback) {
    const collection = db.collection('todos');
    collection.find({}).toArray(function (err, todos) {
        assert.equal(err, null);
        console.log("Found the following records");
        console.log(todos)
        callback(todos);
    });
}

app.get('/', (req, res) => {
    dbClient.connect(function (err) {
        assert.equal(null, err);
        console.log("Connected successfully to server");

        const db = dbClient.db(dbName);

        findTodos(db, function(todosArr) {
            var todos = { todos: todosArr }
            res.send(todos)
            dbClient.close()
        });
    });
});

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

它基本上是从在线教程中复制粘贴的.第一次我对" http://localhost:3000/发出http请求时,此请求有效.但是第二次我得到了

It is basically copy-pasted from online tutorials. First time I make http request to 'http://localhost:3000/' it works. But second time I get

todo-backend/node_modules/mongodb/lib/utils.js:132
    throw err;
    ^

AssertionError [ERR_ASSERTION]: 'MongoError: Topology was destroyed' == null
    at todo-backend/index.js:15:16
    at err (todo-backend/node_modules/mongodb/lib/utils.js:415:14)
    at executeCallback (todo-backend/node_modules/mongodb/lib/utils.js:404:25)
    at handleCallback (todo-backend/node_modules/mongodb/lib/utils.js:128:55)
    at cursor._endSession.cursor._endSession (todo-backend/node_modules/mongodb/lib/operations/cursor_ops.js:207:38)
    at ClientSession.endSession (todo-backend/node_modules/mongodb-core/lib/sessions.js:129:41)
    at Cursor._endSession (todo-backend/node_modules/mongodb-core/lib/cursor.js:189:13)
    at Cursor._endSession (todo-backend/node_modules/mongodb/lib/cursor.js:226:59)
    at cursor._next (todo-backend/node_modules/mongodb/lib/operations/cursor_ops.js:207:20)
    at initializeCursor (todo-backend/node_modules/mongodb-core/lib/cursor.js:766:16)

我在Internet上寻找答案,发现了类似的错误,但是当人们正在做更复杂的事情时.我所做的工作似乎更基础,而且找不到任何可能有所帮助的变更空间.

I have looked over the Internet for answer and found similar error but when people are doing more complicated things. What I did seems for more very basic and I can not find any room for change that might help.

如果我删除了dbClient.close(),它可以工作,但是随后我在MongoDB日志中看到了连接数量不断增长的情况.当然,我可以引入一个标志并检查是否已经连接.但是有了这个问题,我想了解一个根本原因.

If I remove dbClient.close() it works but then I see in MongoDB logs that number of connections is constantly growing. Of course I can introduce a flag and check if I already connected. But with this question I want to understand a root cause.

推荐答案

这是因为代码包含一个反模式:每次有新请求进入时,它都会打开一个新的数据库连接,然后在响应后关闭该连接.寄了,送了.然后,它随后尝试重用已关闭的连接,因此,您在第二个请求上看到的错误消息.

This is because the code contains an anti-pattern: every time a new request comes in, it opens a new database connection, then closes that connection once the response was sent. It then subsequently tried to reuse the closed connection, hence the error message you're seeing on the 2nd request.

您想要的是使用全局连接对象在应用程序的生命周期内仅一次连接到数据库,然后使用该全局对象执行数据库操作.

What you want is to connect only once to the database for the lifetime of the application using a global connection object, then use that global object to perform your database operations.

使用此全局对象可使MongoDB驱动程序正确创建与数据库的连接池.该池由MongoDB驱动程序管理,并避免了昂贵的连接/重新连接模式.

Using this global object allows the MongoDB driver to properly create a connection pool to the database. This pool is managed by the MongoDB driver, and avoids the expensive connect/reconnect pattern.

例如:

// listen on this port
const port = 3000

// global database client object
var client = null

// listen on the configured port once database connection is established
MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true }, (err, res) => {
  assert.equal(null, err)
  client = res
  app.listen(port, () => console.log(`Example app listening on port ${port}!`))
})

// use the client global object for database operations
app.get('/', (req, res) => {
  db = req.query.db
  col = req.query.col
  client.db(db).collection(col).find({}).toArray((err, docs) => {
    assert.equal(null, err)
    res.send(JSON.stringify(docs))
  })
})

编辑以在评论中回答您的问题:

Edit to answer your question in the comment:

为什么每次我都进行连接时它会尝试重用以前的连接?

Why does it tries to reuse previous connection when I do connect every time?

这是因为在原始代码中,dbClient是全局定义的.调用dbClient.close()时,全局dbClient被关闭.重新使用该dbClient对象时,将产生一个错误.这是因为connect()创建一个连接池而不是一个连接,并且每次调用都不会多次被调用.

This is because in the original code, dbClient was globally defined. When dbClient.close() was called, the global dbClient was closed. An error was then produced when that dbClient object was reused. This is because connect() creates a connection pool instead of a single connection, and was not expected to be called multiple times per invocation.

如果将dbClient变量从全局范围移到app.get()上下文中,您将发现多次调用HTTP端点时不会产生任何错误,因为创建了一个新的dbClient对象每次.

If you move the dbClient variable from the global scope into the app.get() context, you'll find that no error will be produced when you call the HTTP endpoint multiple times, as a new dbClient object was created every time.

已经说过,尽管它会起作用,但这不是推荐的模式.最好使用类似于我上面发布的示例代码的模式.

Having said that, although it will work, this is not a recommended pattern. It's better to use a pattern similar to the example code I posted above.

这篇关于“拓扑被破坏".将MongoDB与本机驱动程序和Express.js一起使用时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆