117

I'm preparing a database creation script in Node.js and Mongoose. How can I check if the database already exists, and if so, drop (delete) it using Mongoose?

I could not find a way to drop it with Mongoose.

Flip
  • 6,233
  • 7
  • 46
  • 75
Yaron Naveh
  • 23,560
  • 32
  • 103
  • 158

16 Answers16

178

There is no method for dropping a collection from mongoose, the best you can do is remove the content of one :

Model.remove({}, function(err) { 
   console.log('collection removed') 
});

But there is a way to access the mongodb native javascript driver, which can be used for this

mongoose.connection.collections['collectionName'].drop( function(err) {
    console.log('collection dropped');
});

Warning

Make a backup before trying this in case anything goes wrong!

Oliver Salzburg
  • 21,652
  • 20
  • 93
  • 138
drinchev
  • 19,201
  • 4
  • 67
  • 93
  • 2
    when I try the second option I get "cannot read property 'collectionName' of undefined" – Yaron Naveh Apr 10 '12 at 12:10
  • You are right, sorry for that the correct code is mongoose.connection.collections['collectionName'].drop( function(err) { }); – drinchev Apr 10 '12 at 12:25
  • thanks, this works, but I still need to declare the schemas and all before calling it. isn't there something more brute force? – Yaron Naveh Apr 10 '12 at 12:36
  • 1
    Since all collections are in the hash mongoose.connection.collections, you might simply list them for ( collection in mongoose.connection.collections ) { mongoose.connection.collections[collection].drop } ... smth similar – drinchev Apr 10 '12 at 12:42
  • Also, you don't have to list the schema to access your collections from there, you just need a valid connection, without further mongoose.model declarations! – drinchev Apr 10 '12 at 12:50
  • 3
    You've got a typo -- an extra comma after the function(err)... should be: mongoose.connection.collections['collectionName'].drop( function(err) { console.log('collection dropped'); }); – arxpoetica Aug 19 '12 at 02:53
  • 9
    Am i the only one that realized this answer does not address the question of how to drop a database. Its not asking to drop a collection its asking to drop a database.. – Joseph Persico Oct 12 '13 at 05:58
  • 1
    For some reason, I get this error `TypeError: Cannot call method 'drop' of undefined`. Not sure what I am doing wrong. – SSH This Apr 11 '14 at 20:18
  • Oh I misclicked on downvote button, and I understood 15 minutes later :/ can you edit it please? – Vinz243 Sep 11 '14 at 18:02
  • 1
    If you get "cannot read property 'collectionName' of undefined" try:mongoose.connection.collection(collectionName).drop(function(err) { if (err) { console.log("err:", err); } }); – Daniele Urania Jan 13 '15 at 15:54
  • 6
    "There is no method for dropping a collection from mongoose", first of all the OP wants to delete a database, not a colledtion, second the answer of @hellslam below works well. – SCBuergel Feb 26 '17 at 13:03
98

Mongoose will create a database if one does not already exist on connection, so once you make the connection, you can just query it to see if there is anything in it.

You can drop any database you are connected to:

var mongoose = require('mongoose');
/* Connect to the DB */
mongoose.connect('mongodb://localhost/mydatabase',function(){
    /* Drop the DB */
    mongoose.connection.db.dropDatabase();
});
Code Whisperer
  • 22,959
  • 20
  • 67
  • 85
hellslam
  • 1,550
  • 11
  • 17
  • 1
    I tried `mongoose.connection.db.dropDatabase()` but I found the db is still there? Do I miss something? – Freewind May 10 '12 at 15:04
  • If you connected to it afterward it would be recreated, though empty. Were there any collections in it after you dropped it? – hellslam May 10 '12 at 18:34
  • Are you using the same connection throughout, or creating multiple connections? – hellslam May 16 '12 at 19:47
  • 12
    I found the `dropDatabase` invocation should be placed in the callback of `connect`, as `mongoose.connect('...', function() { ...dropDatabase()})`. – Freewind May 17 '12 at 01:29
  • 1
    dropDatabase seems not work in some cases, but direct mongo command still can be used `mongoose.connection.db.executeDbCommand( {dropDatabase:1}, function(err, result) { if (err) { console.log(err); } done(); });` – farincz May 29 '14 at 09:55
17

If you modify @hellslam's solution like this then it will work

I use this technique to drop the Database after my integration tests

//CoffeeScript
mongoose = require "mongoose"
conn = mongoose.connect("mongodb://localhost/mydb")

conn.connection.db.dropDatabase()

//JavaScript
var conn, mongoose;
mongoose = require("mongoose");
conn = mongoose.connect("mongodb://localhost/mydb");

conn.connection.db.dropDatabase();

HTH at least it did for me, so I decided to share =)

Setthase
  • 13,988
  • 2
  • 27
  • 30
silverfighter
  • 6,762
  • 10
  • 46
  • 73
  • is it possible to drop db with this? `db = mongoose.createConnection(cfg.mongo.uri, cfg.mongo.db);` – chovy Nov 10 '12 at 09:58
  • 2
    This was helpful, thanks! However, your variable names are a little misleading... `mongoose.connect` actually returns `mongoose`. Instead of `conn = mongoose.connect(...)` I'd write `mongoose.connect(...)` and then `conn = mongooose.connection`. – a paid nerd Aug 07 '13 at 17:45
  • I don't think this code will always work because the `connect` is asynchronous. So if the connection doesn't happen immediately, the dropDatabase() command will fail. That's why the other solutions above recommended putting the `dropDatabase` command in the callback to the `connect` statement or an `open` event handler. – Mark Stosberg Mar 17 '17 at 14:14
9

Tried @hellslam's and @silverfighter's answers. I found a race condition holding my tests back. In my case I'm running mocha tests and in the before function of the test I want to erase the entire DB. Here's what works for me.

var con = mongoose.connect('mongodb://localhost/mydatabase');
mongoose.connection.on('open', function(){
    con.connection.db.dropDatabase(function(err, result){
        done();
    });
});

You can read more https://github.com/Automattic/mongoose/issues/1469

zafrani
  • 4,030
  • 5
  • 31
  • 39
8

An updated answer, for 4.6.0+, if you have a preference for promises (see docs):

mongoose.connect('mongodb://localhost/mydb', { useMongoClient: true })
.then((connection) => {
   connection.db.dropDatabase();
   // alternatively:
   // mongoose.connection.db.dropDatabase();
});

I tested this code in my own code, using mongoose 4.13.6. Also, note the use of the useMongoClient option (see docs). Docs indicate:

Mongoose's default connection logic is deprecated as of 4.11.0. Please opt in to the new connection logic using the useMongoClient option, but make sure you test your connections first if you're upgrading an existing codebase!

Andre M
  • 6,649
  • 7
  • 52
  • 93
5

The difficulty I've had with the other solutions is they rely on restarting your application if you want to get the indexes working again.

For my needs (i.e. being able to run a unit test the nukes all collections, then recreates them along with their indexes), I ended up implementing this solution:

This relies on the underscore.js and async.js libraries to assemble the indexes in parellel, it could be unwound if you're against that library but I leave that as an exerciser for the developer.

mongoose.connection.db.executeDbCommand( {dropDatabase:1}, function(err, result) {
  var mongoPath = mongoose.connections[0].host + ':' + mongoose.connections[0].port + '/' + mongoose.connections[0].name
  //Kill the current connection, then re-establish it
  mongoose.connection.close()
  mongoose.connect('mongodb://' + mongoPath, function(err){
    var asyncFunctions = []

    //Loop through all the known schemas, and execute an ensureIndex to make sure we're clean
    _.each(mongoose.connections[0].base.modelSchemas, function(schema, key) {
      asyncFunctions.push(function(cb){
        mongoose.model(key, schema).ensureIndexes(function(){
          return cb()
        })
      })
    })

    async.parallel(asyncFunctions, function(err) {
      console.log('Done dumping all collections and recreating indexes')
    })
  })
})
Eric Caron
  • 6,181
  • 1
  • 24
  • 26
5

This works for me as of Mongoose v4.7.0:

mongoose.connection.dropDatabase();
user3344977
  • 3,584
  • 4
  • 32
  • 88
5

2020 update

make a new file call it drop.js i.e and put inside

require('dotenv').config()
const url = process.env.ATLAS_URI;
mongoose.connect(url, {
  useNewUrlParser: true,
  useCreateIndex: true,
  useUnifiedTopology: true,
  useFindAndModify: false
});

const connection = mongoose.connection;
connection.once('open', () => {
  console.log("MongoDB database connection established successfully");
})


mongoose.connection.dropDatabase().then(
  async() => {
   
    try {
      mongoose.connection.close()
     
    }
    catch (err) {
      console.log(err)
    }

 }
  
);

in your package.json

in your package.json 
 "scripts": {
    
    "drop": "node models/drop.js",
   
  }

run it on ur console and

Adam
  • 113
  • 1
  • 8
  • if u just write mongoose.connection.dropDatabase you would be stuck in and you conc will be still open so if you want to close it u shold handle the promise u got from it with try and catch to stay away from this err Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. – Adam Dec 10 '20 at 06:37
4

To empty a particular collection in a database:

model.remove(function(err, p){
    if(err){ 
        throw err;
    } else{
        console.log('No Of Documents deleted:' + p);
    }
});

Note:

  1. Choose a model referring to particular schema(schema of collection you wish to delete).
  2. This operation will not delete collection name from database.
  3. This deletes all the documents in a collection.
Danish
  • 503
  • 3
  • 14
4

The best way to drop your database in Mongoose depends on which version of Mongoose you are using. If you are using a version of Mongoose that 4.6.4 or newer, then this method added in that release is likely going to work fine for you:

mongoose.connection.dropDatabase();

In older releases this method did not exist. Instead, you were to use a direct MongoDB call:

mongoose.connection.db.dropDatabase();

However, if this was run just after the database connection was created, it could possibly fail silently. This is related to the connection actually be asynchronous and not being set up yet when the command happens. This is not normally a problem for other Mongoose calls like .find(), which queue until the connection is open and then run.

If you look at the source code for the dropDatabase() shortcut that was added, you can see it was designed to solve this exact problem. It checks to see if the connection is open and ready. If so, it fires the command immediately. If not, it registers the command to run when the database connection has opened.

Some of the suggestions above recommend always putting your dropDatabase command in the open handler. But that only works in the case when the connection is not open yet.

Connection.prototype.dropDatabase = function(callback) {
  var Promise = PromiseProvider.get();
  var _this = this;
  var promise = new Promise.ES6(function(resolve, reject) {
    if (_this.readyState !== STATES.connected) {
      _this.on('open', function() {
        _this.db.dropDatabase(function(error) {
          if (error) {
            reject(error);
          } else {
            resolve();
          }
        });
      });
    } else {
      _this.db.dropDatabase(function(error) {
        if (error) {
          reject(error);
        } else {
          resolve();
        }
      });
    }
  });
  if (callback) {
    promise.then(function() { callback(); }, callback);
  }
  return promise;
};

Here's a simple version of the above logic that can be used with earlier Mongoose versions:

// This shim is backported from Mongoose 4.6.4 to reliably drop a database
// http://stackoverflow.com/a/42860208/254318
// The first arg should be "mongoose.connection"
function dropDatabase (connection, callback) {
    // readyState 1 === 'connected'
    if (connection.readyState !== 1) {
      connection.on('open', function() {
        connection.db.dropDatabase(callback);
      });
    } else {
      connection.db.dropDatabase(callback);
    }
}  
Mark Stosberg
  • 12,961
  • 6
  • 44
  • 49
3

Mongoose 4.6.0+:

mongoose.connect('mongodb://localhost/mydb')
mongoose.connection.once('connected', () => {
    mongoose.connection.db.dropDatabase();
});

Passing a callback to connect won't work anymore:

TypeError: Cannot read property 'commandsTakeWriteConcern' of null

Rayjax
  • 7,494
  • 11
  • 56
  • 82
  • 1
    `connect` returns a promise, so you can add `.then((connection) => { ... });` to the `mongoose.connect`. See: http://mongoosejs.com/docs/connections.html – Andre M Dec 12 '17 at 18:35
1
beforeEach((done) => {
      mongoose.connection.dropCollection('products',(error ,result) => {
      if (error) {
        console.log('Products Collection is not dropped')
      } else {
        console.log(result)
      }
    done()
    })
  })
Revt A
  • 11
  • 1
1

To drop all documents in a collection:

await mongoose.connection.db.dropDatabase();

This answer is based off the mongoose index.d.ts file:

dropDatabase(): Promise<any>;
mrhid3f
  • 11
  • 1
1
mongoose.connect(`mongodb://localhost/${dbname}`, {
        useNewUrlParser: true,
        useCreateIndex: true,
        useFindAndModify: true,
        useUnifiedTopology: true
    })
        .then((connection) => {
            mongoose.connection.db.dropDatabase();
        });

To delete a complete database, just pass the name... This one is working perfectly fine on version 4.4

Uzair Ali
  • 11
  • 3
0

Since the remove method is depreciated in the mongoose library we can use the deleteMany function with no parameters passed.

Model.deleteMany();

This will delete all content of this particular Model and your collection will be empty.

-2

For dropping all documents in a collection:

myMongooseModel.collection.drop();

as seen in the tests

Sgnl
  • 1,808
  • 22
  • 30