dropCollection执行无效:删除后仍查询到集合的问题排查
问题:删除数据库所有集合后仍能查询到集合
我编写了一段用于删除数据库中所有集合的代码,预期执行后调用collections()会返回空集合,但实际仍能查询到集合。
代码示例
const collectionsBeforeDrop = await db.collections(); collectionsBeforeDrop.forEach(async (c) => { console.log(`got collection name : ${c.collectionName}`); await db.dropCollection(c); }); console.log(`checking after cleanup`) const collectionsAfterDrop = await db.collections(); collectionsAfterDrop.forEach(c => { console.log(`got collection name after claanup! THIS SHOULDN'T HAVE HAPPENED : ${util.inspect(c.collectionName)}`); //THIS CODE HITS throw new Error("couldn't clean up after test case"); });
执行输出
cleaning up at Object.log (test/question.test.js:61:13) console.log got db [object Object] at Object.log (test/question.test.js:64:13) console.log truncating collections of db Questions at Object.log (test/question.test.js:67:13) console.log got collection name : areas at log (test/question.test.js:72:15) at Array.forEach (<anonymous>) console.log checking after cleanup at Object.log (test/question.test.js:75:13) console.log got collection name after claanup! THIS SHOULDN'T HAVE HAPPENED : 'areas' at log (test/question.test.js:78:15) at Array.forEach (<anonymous>)
问题原因
核心问题是**Array.forEach不支持等待异步函数完成**。你在forEach里传入了async回调函数,forEach会立刻遍历执行所有回调,但不会等待这些异步的删除操作全部完成,就直接跳到后续的集合查询代码。所以你查询集合的时候,删除操作可能还没跑完,自然能看到残留的集合。
修复方案
可以用两种方式解决:
方案1:使用for...of循环
for...of可以配合await,确保每个删除操作完成后再执行下一个:
const collectionsBeforeDrop = await db.collections(); // 用for...of逐个等待删除完成 for (const c of collectionsBeforeDrop) { console.log(`got collection name : ${c.collectionName}`); await db.dropCollection(c); } console.log(`checking after cleanup`) const collectionsAfterDrop = await db.collections(); collectionsAfterDrop.forEach(c => { console.log(`got collection name after cleanup! THIS SHOULDN'T HAVE HAPPENED : ${util.inspect(c.collectionName)}`); throw new Error("couldn't clean up after test case"); });
方案2:使用Promise.all
把所有删除操作包装成Promise数组,用Promise.all等待全部操作完成:
const collectionsBeforeDrop = await db.collections(); // 批量等待所有删除操作完成 await Promise.all(collectionsBeforeDrop.map(async (c) => { console.log(`got collection name : ${c.collectionName}`); await db.dropCollection(c); })); console.log(`checking after cleanup`) const collectionsAfterDrop = await db.collections(); collectionsAfterDrop.forEach(c => { console.log(`got collection name after cleanup! THIS SHOULDN'T HAVE HAPPENED : ${util.inspect(c.collectionName)}`); throw new Error("couldn't clean up after test case"); });
内容的提问来源于stack exchange,提问作者Manu Chadha
相关产品推荐
相关产品推荐

