mongoose.connection.collections.collection.drop()每隔一段时间抛出一次错误

问题描述 投票:4回答:2

我正在使用Jest为Node / Express / Mongo项目设置测试。我试图写一个函数来清除集合,所以每个测试都以一个干净的平板开始:

const clearCollection = (collectionName, done) => {
  const collection = mongoose.connection.collections[collectionName]
  collection.drop(err => {
    if (err) throw new Error(err)
    else done()
  )
}

beforeEach(done => {
  clearCollection('users', done)
})

另一个尝试,承诺:

const clearCollection = collectionName => {
  const collection = mongoose.connection.collections[collectionName]
  return collection.drop()
}

beforeEach(async () => {
  await clearCollection('users')
})

问题是它们在工作和抛出错误之间交替。每次我保存文件时,它都可以正常工作,或者每次都交替抛出错误。错误始终是以下之一:

MongoError: cannot perform operation: a background operation is currently running for collection auth_test.users

MongoError: ns not found

通过让clearCollection()catch()中调用自己,我可以让它在100%的时间内工作(无论如何都受到堆栈限制),但这感觉很错误:

const clearCollection = collectionName => {
  const collection = mongoose.connection.collections[collectionName]
  return collection.drop()
    .catch(() => clearCollection(collectionName))
}
node.js mongodb mongoose promise async-await
2个回答
2
投票

我不知道为什么mongoose.connection.collections.<collection>.drop()会随机抛出错误,但是有一种简单的方法可以删除Mongoose中的所有文件,这对于在测试之前重置集合非常有用:

beforeAll(async () => {
  await User.remove({})
})

每次都有效。


0
投票

尝试在测试开始时删除数据库并在之后填充数据库时,我遇到了类似的问题。在第一次运行中,将创建集合;在下一个,我会得到一个错误,'数据库正在被丢弃。'; ......它像这样交替。

我还在使用“内存”Mongodb,在运行我的Mocha测试之前在单独的终端窗口中运行$ run-rs -v 4.0.0 -shttps://www.npmjs.com/package/run-rs)。另外,我在这里有Mongoose 5.2.0和Mocha 5.1.1。

我发现Mongoose不一定立即执行drop命令。相反,它会在连接启动时安排它们。

因此,可能存在竞争条件,其中drop命令的承诺得到解决,并且您继续执行代码,直到达到创建集合的指令...但是drop命令尚未完成运行,并且您'将获得创建新集合的错误。运行完成后,下次运行测试时,您的数据库(或集合)已被删除,因此您将能够再次插入新集合。

所以,这就是我解决的问题......

在前钩子中运行:

test.dropDb = function(done) {
    this.timeout(0)

    let database = your_MongoDB_URI
    mongoose.connect(database, function (err) {
        if (err) throw err;
        mongoose.connection.db.dropDatabase(function(err, result){
            console.log('database dropping was scheduled');
        });
    })
    mongoose.connection.on('connected', function() {
        setTimeout(function(){ done() }, 3000);
    });
}

在嵌套之前运行钩子

test.createDb = function(done) {
    this.timeout(0)

    let createDb = require('./create-db.js')
    createDb() // here I call all my MyCollections.insertMany(myData)...
    .then( function() {
        done()
    })
    .catch( function(err) {
        assert( null == err)
    });
}

在后钩中运行

test.afterAll = function(done) {    
    mongoose.connection.close()
    .then( function() {
        done()
    })
}

我不知道为什么我必须在挂钩后显式关闭连接。我想这与run-rs的编程方式有关,但我没有调查它。我只知道,在我的情况下,在测试之后关闭连接是强制性的,以获得预期的行为。

© www.soinside.com 2019 - 2024. All rights reserved.