【问题标题】:How to fix MongoError: Cannot use a session that has ended如何修复 MongoError:无法使用已结束的会话
【发布时间】:2020-05-06 01:12:08
【问题描述】:

我正在尝试使用 Node.js 从 MongoDB Atlas 集合中读取数据。当我尝试阅读我收藏的内容时,我收到错误MongoError: Cannot use a session that has ended。这是我的代码

client.connect(err => {
    const collection = client
        .db("sample_airbnb")
        .collection("listingsAndReviews");

    const test = collection.find({}).toArray((err, result) => {
        if (err) throw err;
    });
    client.close();
});

我能够查询特定文档,但我不确定如何返回集合的所有文档。我已经搜索过这个错误,我找不到太多关于它的内容。谢谢

【问题讨论】:

  • 你能分享你的 indes.js 文件吗?
  • 我已经分享了所有相关的代码@MaheshBhatnagar

标签: node.js mongodb mongodb-atlas


【解决方案1】:

在您的代码中,它不会等待find() 完成其执行并继续执行client.close() 语句。因此,当它尝试从数据库中读取数据时,连接已经结束。我遇到了同样的问题并像这样解决了它:

// connect to your cluster
const client = await MongoClient.connect('yourMongoURL', { 
    useNewUrlParser: true, 
    useUnifiedTopology: true,
});
// specify the DB's name
const db = client.db('nameOfYourDB');
// execute find query
const items = await db.collection('items').find({}).toArray();
console.log(items);
// close connection
client.close();

编辑:这整件事应该在 async 函数中。

【讨论】:

  • 我的意思是你应该把它写在一个异步函数中,因为你正在使用等待。如下:const findItems = async () => { // write above code here };
【解决方案2】:

当我将 MongoClient 从 3.3.2 更新到最新版本(撰写本文时为 3.5.2)时遇到了同样的问题。要么通过更改 package.json "mongodb": "3.3.2", 仅安装 3.3.2 版本,要么只使用异步和等待包装器。

如果问题仍然存在,请移除 node_modules 并重新安装。

【讨论】:

  • 您的解决方案也对我有用,我三次检查了所有异步等待功能,但在将版本降级到 3.3.2 之前仍然出现相同的错误。谢谢!
【解决方案3】:

一种选择是使用Promise 链。 collection.find({}).toArray() 既可以接收回调函数也可以返回一个 Promise,因此您可以使用 .then() 链接调用

collection.find({}).toArray() // returns the 1st promise
.then( items => {
    console.log('All items', items);
    return collection.find({ name: /^S/ }).toArray(); //return another promise
})
.then( items => {
    console.log("All items with field 'name' beginning with 'S'", items);
    client.close(); // Last promise in the chain closes the database
);

当然,这种菊花链使代码更加同步。当链中的下一个调用与前一个调用相关时,这很有用,例如在第一个调用中获取用户 ID,然后在下一个调用中查找用户详细信息。

应该并行(异步)执行几个不相关的查询,当所有结果返回时,处理数据库连接。 例如,您可以通过跟踪数组或计数器中的每个调用来做到这一点。

const totalQueries = 3;
let completedQueries = 0;

collection.find({}).toArray()
.then( items => {
    console.log('All items', items);
    dispose(); // Increments the counter and closes the connection if total reached
})

collection.find({ name: /^S/ }).toArray()
.then( items => {
    console.log("All items with field 'name' beginning with 'S'", items);
    dispose(); // Increments the counter and closes the connection if total reached
);

collection.find({ age: 55 }).toArray()
.then( items => {
    console.log("All items with field 'age' with value '55'", items);
    dispose(); // Increments the counter and closes the connection if total reached
);

function dispose(){
    if (++completedQueries >= totalQueries){
        client.close();
    }
}

您有 3 个查询。当每个人调用dispose() 时,计数器就会增加。当他们都调用dispose() 时,最后一个也将关闭连接。

Async/Await 应该更容易,因为它们从 then 函数解包 Promise 结果。

async function test(){
    const allItems = await collection.find({}).toArray();
    const namesBeginningWithS = await collection.find({ name: /^S/ }).toArray();
    const fiftyFiveYearOlds = await collection.find({ age: 55 }).toArray();
    client.close();
}

test();

下面是一个示例,说明 Async/Await 如何通过在调用下一个异步函数之前等待一个异步函数完成而最终使异步代码按顺序运行并低效运行,而理想情况是立即调用它们并且只等待直到它们都完成为止。

let counter = 0;

function doSomethingAsync(id, start) {
  return new Promise(resolve => {
    setTimeout(() => {
      counter++;
      const stop = new Date();    
      const runningTime = getSeconds(start, stop);
      resolve(`result${id} completed in ${runningTime} seconds`);
    }, 2000);
  });
}

function getSeconds(start, stop) {
  return (stop - start) / 1000;
}

async function test() {
  console.log('Awaiting 3 Async calls');
  console.log(`Counter before execution: ${counter}`);
  
  const start = new Date();
  
  let callStart = new Date();
  const result1 = await doSomethingAsync(1, callStart);
  
  callStart = new Date();
  const result2 = await doSomethingAsync(2, callStart);
  
  callStart = new Date();
  const result3 = await doSomethingAsync(3, callStart);
  
  const stop = new Date();

  console.log(result1, result2, result3);
  console.log(`Counter after all ran: ${counter}`);
  console.log(`Total time to run: ${getSeconds(start, stop)}`);
 }

test();

注意:像上面示例中的等待会再次使调用按顺序进行。如果每个运行需要 2 秒,则该函数需要 6 秒才能完成。

结合所有世界中最好的,您可能希望在立即运行所有调用的同时使用 Async/Await。幸好Promise有办法做到这一点,所以test()可以这样写:-

async function test(){
    let [allItems, namesBeginningWithS, fiftyFiveYearOlds] = await Promise.all([
        collection.find({}).toArray(),
        collection.find({ name: /^S/ }).toArray(),
        collection.find({ age: 55 }).toArray()
    ]);

    client.close();
}

这是一个演示性能差异的工作示例:-

let counter = 0;

function doSomethingAsync(id, start) {
  return new Promise(resolve => {
    setTimeout(() => {
      counter++;
      const stop = new Date();    
      const runningTime = getSeconds(start, stop);
      resolve(`result${id} completed in ${runningTime} seconds`);
    }, 2000);
  });
}

function getSeconds(start, stop) {
  return (stop - start) / 1000;
}

async function test() {
  console.log('Awaiting 3 Async calls');
  console.log(`Counter before execution: ${counter}`);
  const start = new Date();
  
  const [result1, result2, result3] = await Promise.all([
        doSomethingAsync(1, new Date()),
        doSomethingAsync(2, new Date()),
        doSomethingAsync(3, new Date())
  ]);
  
  const stop = new Date();

  console.log(result1, result2, result3);
  console.log(`Counter after all ran: ${counter}`);
  console.log(`Total time to run: ${getSeconds(start, stop)}`);
 }

test();

【讨论】:

  • toArray().then( 好方法这么短。
【解决方案4】:

其他人已经谈到了这一点,但我只想强调 .toArray() 是异步执行的,因此您需要确保在关闭会话之前它已经完成

这行不通

const randomUser = await db.collection('user').aggregate([ { $sample: { size: 1 } } ]);
console.log(randomUser.toArray()); 
await client.close();

这会

const randomUser = await db.collection('user').aggregate([ { $sample: { size: 1 } } ]).toArray();
console.log(randomUser); 
await client.close();

【讨论】:

    【解决方案5】:
    client.connect(err => {
        const collection = client
            .db("sample_airbnb")
            .collection("listingsAndReviews");
    
        const test = collection.find({}).toArray((err, result) => {
            if (err) throw err;
    
            client.close();
    
        });        
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-11
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多