When the collection doesn't exist when drop()
is called, an error is thrown:
ns not found
Currently I'm using something like
try {
await MongooseModel.collection.drop();
} catch (err) {
if (err.message !== 'ns not found') {
throw err;
}
}
which doesn't smell too good. It's not really clear why an error is thrown in the first place, I would expect that drop()
will return false
if it didn't exist, like it's done in Mongo console.
How can this be done when there is only a reference to Mongoose model, MongooseModel
?
I don't have a reference to connection object in the place where I'm doing this, like is suggested in this answer.
Using the DB Class In order to connect to the database, we just need to specify the database name. If the database is not present, MongoDB will automatically create one. Here, the collectionExists method will return true if the collection exists, false otherwise.
The collectionNames method of the native driver's Db object accepts an optional collection name filter as a first parameter to let you check the existence of a collection: db. collectionNames(collName, function(err, names) { console. log('Exists: ', names.
Mongoose | exists() Function The exists() function returns true if at least one document exists in the database that matches the given filter, and false otherwise.
In MongoDB, we can check the existence of the field in the specified collection using the $exists operator.
Actually you do have the reference. You can mongoose.connection
at any time after a connection is established and return the current connection.
You can also simply grab the db
from any model instance. So an approach you can use if you don't want to try..catch
on errors when the collection does not exist, is to basically use the .listCollections()
method from the underlying driver in order to see if the collection you want to access actually exists in the namespace first:
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();
}
Would demonstrate that the first attempted collection drop does not exist, without throwing an error:
Mongoose: modelbs.insert({ a: 1, _id: ObjectId("59aa9cfe581cca7afac55181"), __v: 0 })
collection modelas does not exist
Mongoose: modelbs.drop()
There are other things you can do such as use .collection()
from the underlying driver with { strict: true }
to get a collection object first. But again this really only "throws an error". So whilst you would "know" before issuing the .drop()
that the collection does not exist, it's still the same try..catch
handling required.
So for no errors, check for the presence of the collection first. Provided nothing else is going to remove it of course. But you probably should always error handle just in case.
Personally I do find it simply cleaner to allow the exception to occur and then simply inspect the details to see that the exception being raised is what I expect:
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;
}
}
}
In this case code: 26
for "Namespace not found"
, which would be raised in this case or in the case using the native .collection()
method with { strict: true }
as well. But using .drop()
of the existing handle to the collection object is much shorter.
Point being that nothing requires you to actually log the exception, and "inspecting exceptions" ( i.e Expected duplicate key errors in bulk inserts ) is a common practice. Just test for the expected error code, and "if" something else is returned then you raise the exception at a higher level.
As stated earlier, whilst you "can" make the presumption that if you ask the database to list the collection by name and it's in the results then it exists, the safest course is to still catch any exception from the I/O in case there is some other modification in between the "query" and the "operation" to remove.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With