在放入猫鼬之前检查集合是否存在

Est*_*ask 5 mongoose mongodb node.js

当drop()调用集合不存在时,将引发错误:

找不到ns

目前我正在使用类似

try {
    await MongooseModel.collection.drop();
} catch (err) {
    if (err.message !== 'ns not found') {
        throw err;
    }
}
Run Code Online (Sandbox Code Playgroud)

闻起来不太香 目前尚不清楚为什么会首先引发错误,如果不存在该错误,我希望它drop()会返回false,就像在Mongo控制台中所做的那样。

当仅引用Mongoose模型时,该MongooseModel怎么办?

我在执行此操作的地方没有对连接对象的引用,就像在此答案中建议的那样。

Nei*_*unn 6

实际上,您确实有参考。mongoose.connection建立连接后,您可以随时返回当前连接。

您也可以简单地db从任何模型实例中获取。因此,如果不想try..catch在集合不存在时出错就可以使用的.listCollections()一种方法是,基本上使用底层驱动程序中的方法,以便首先查看要访问的集合是否确实存在于命名空间中:

const mongoose = require('mongoose'),
      Schema = mongoose.Schema;

mongoose.Promise = global.Promise;
mongoose.set('debug',true);

const uri = 'mongodb://localhost/blank',
      options = { useMongoClient: true };

const testSchema = new Schema({},{ strict: false });

const ModelA = mongoose.model('ModelA', testSchema);
const ModelB = mongoose.model('ModelB', testSchema);

(async function() {

  try {

    const conn = await mongoose.connect(uri,options);


    await ModelB.create({ a: 1 });


    for ( let model of [ModelA,ModelB] ) {

      let list = await model.db.db.listCollections({
        name: model.collection.name
      }).toArray()
      //console.log(JSON.stringify(list,undefined,2));

      if ( list.length !== 0 ) {
        await model.collection.drop();
      } else {
        console.log('collection %s does not exist',model.collection.name);
      }

    }


  } catch(e) {
    console.error(e);
  } finally {
    mongoose.disconnect();
  }
Run Code Online (Sandbox Code Playgroud)

将证明不存在第一次尝试的收集删除,而不会引发错误:

Mongoose: modelbs.insert({ a: 1, _id: ObjectId("59aa9cfe581cca7afac55181"), __v: 0 })
collection modelas does not exist
Mongoose: modelbs.drop()
Run Code Online (Sandbox Code Playgroud)

您还可以执行其他操作,例如.collection()从基础驱动程序使用{ strict: true }来首先获取集合对象。但是,这实际上只是“引发错误”。因此,尽管您在发出该.drop()集合不存在之前会“知道” ,但仍try..catch需要进行相同的处理。

因此,如果没有错误,请首先检查集合是否存在。只要没有其他东西可以删除它,当然。但是为了以防万一,您可能应该始终进行错误处理。


就我个人而言,我确实发现它更干净,可以允许发生异常,然后仅检查详细信息以查看所引发的异常是我所期望的:

for ( let model of [ModelA,ModelB] ) {
  try {
    await model.collection.drop();
  } catch (e) {
    if (e.code === 26) {
      console.log('namespace %s not found',model.collection.name)
    } else {
      throw e;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,code: 26对于"Namespace not found",在这种情况下或者在使用native .collection()方法的情况下也将引发{ strict: true }。但是,使用.drop()集合对象的现有句柄要短得多。

要点是,什么都不需要您实际记录异常,而“检查异常”(即,批量插入中预期的重复键错误)是一种常见的做法。只需测试预期的错误代码,然后“如果”返回其他内容,则可以在更高级别上引发异常。

如前所述,虽然您可以“假设”要求数据库按名称列出集合并且它存在于结果中,然后它存在,但是最安全的方法仍然是从I / O捕获任何异常是在“查询”和“操作”之间删除的其他一些修改。

  • 谢谢。`(await model.db.db.listCollections({name:...})。toArray())。length`确实可以工作,但是对于这样的基本任务是非常麻烦的。try ... catch看起来也不太好,因为应该根据错误消息声明错误(此处为通用MongoError)。希望有更好的方法。 (2认同)