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

时间:2017-03-23 06:34:50

标签: node.js mongodb mongoose promise async-await

我正在使用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

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

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

2 个答案:

答案 0 :(得分:2)

我不知道为什么beforeAll(async () => { await User.remove({}) }) 会随机抛出错误,但有一种简单的方法可以删除Mongoose中的所有文件,这对于在测试之前重置集合非常有用:

SO()

每次都有效。

答案 1 :(得分: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()
    })
}

我不知道为什么我必须在after钩子中显式关闭连接。我想这与run-rs的编程方式有关,但我没有对此进行研究。我只是知道,就我而言,必须在测试后关闭连接才能获得预期的行为。