57

I need to check if a collection exists on a certain database and create it if it doesn't. I know that

db.createCollection(collName, {strict:true}, function(error, collection))

checks for existance of collection collName before creating it and sets error object. but I need an independent function to check that.

JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
Nasser Torabzade
  • 6,490
  • 8
  • 27
  • 36

12 Answers12

67

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.length > 0);
});

In the 2.x version of the MongoDB native driver, collectionNames has been replaced by listCollections which accepts a filter and returns a cursor so you would do this as:

db.listCollections({name: collName})
    .next(function(err, collinfo) {
        if (collinfo) {
            // The collection exists
        }
    });
JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
25

Using mongo-native driver and Node.js 7.6+, I use the following:

const collections = await db.collections();
if (!collections.map(c => c.s.name).includes(collName)) {
    await db.createCollection(collName);
}

EDIT

As @MattCochrane mentions, collection.s.name is no longer available; as @JohnnyHK and @weekens point out, the correct way is to use the listCollections() method:

const client = new MongoClient(connectionString, { useUnifiedTopology: true });
await client.connect();
const collections = await client.db().listCollections().toArray();
const collectionNames = collections.map(c => c.name);

listCollection() takes an optional filter.

ChrisV
  • 8,748
  • 3
  • 48
  • 38
  • Just tested this Node v8.11.4 - mongodb - 3.1.10: and it works great! – hanbot Jan 15 '19 at 14:16
  • 1
    You could make this a little shorter with `some()` instead of `map` and `includes` https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some – Lukas Aug 24 '20 at 21:12
  • **This no longer works in mongodb 3.6.0**, the `name` property is not available on `collection.s` . A lesson for me.. I should have known better than to use what is clearly not intended to be a public interface. – MattCochrane Oct 18 '20 at 04:18
19

In MongoDB 3.0 and later, you have to run a command to list all collections in a database:

use test;
db.runCommand( { listCollections: 1 } );

Although querying system.namespaces will still work when you use the default storage engine (MMAPv1), it is not guaranteed to work for other engines, such as WiredTiger.

Before MongoDB 3.0 you need to do the following:

You can query the system.namespaces collection:

use test;
db.system.namespace.find( { name: 'test.' + collName } );

Like in:

db.system.namespaces.find( { name: 'test.testCollection' } );

Which returns:

{ "name" : "test.testCollection", "options" : { "flags" : 1 } }

Or of course, nothing.

See also: https://github.com/mongodb/specifications/blob/master/source/enumerate-collections.rst

Derick
  • 35,169
  • 5
  • 76
  • 99
  • 4
    in [mongo-native](https://github.com/mongodb/node-mongodb-native): `db.collection('system.namespaces').find().toArray(function(err, items) {})` – Nasser Torabzade Jan 09 '14 at 16:44
  • Late to the party, but I think my answer below (http://stackoverflow.com/a/40141321/446717) has a more direct and clean approach to get that info – Roberto Oct 19 '16 at 20:53
  • None of this in the answer is available in the native node.js lib. Only working thing is what Nasser provided. – Daniel W. Feb 16 '17 at 10:26
  • As of today, this answer no longer holds valid, ` db.listCollections({name: collName}) .next(function(err, collinfo) { if (collinfo) { // The collection exists } }); ` is a valid answer from [this answer](https://stackoverflow.com/a/28921019/3861525) – trojanh May 13 '19 at 10:42
  • how do you get this db object in nodejs? – Tarun Apr 17 '20 at 14:26
6

Since MongoDB 3.0 you can simply run:

db.getCollectionNames()

which returns an array with the names of all the collections on current database:

[ "employees", "products", "mylogs"]

check Mongo DB Documentation, or you could also use db.getCollectionInfos() if you need more info about each collection

Roberto
  • 2,115
  • 24
  • 32
  • 7
    The method `getCollectionNames()` is not available in node.js native lib. – Daniel W. Feb 16 '17 at 10:24
  • 1
    Hey, but I'm using it from mongodb lib, which is the one that manages the mongo database @DanFromGermany – Roberto Feb 16 '17 at 18:51
  • There is [`Db.collectionNames()`](https://mongodb.github.io/node-mongodb-native/markdown-docs/collections.html#list-existing-collections) in the older API available but not `getCollectionNames()` at all. – Daniel W. Feb 17 '17 at 08:42
  • Which version of MongoDB are you using, this getCollectionNames() exists in MongoDB 3.0 – Roberto Feb 23 '17 at 21:07
  • 3
    Dude, the latest node driver for mongo is [`2.2` (link)](https://mongodb.github.io/node-mongodb-native/). 3.0 does not even exist. – Daniel W. Feb 24 '17 at 08:36
5

There is now a listCollections method in Node.js native driver. It returns information on all collections in current database. You can use it to check if a given collection is there:

collectionExists = function(name, cb) {
  mongoDb.listCollections().toArray(function(err, collections) {
    if (err) return cb(err);

    cb(null, collections.some(function(coll) {
      return coll.name == name;
    }));
  });
}
weekens
  • 8,064
  • 6
  • 45
  • 62
  • @NikolaLukic in `cb` function, first argument is an error (`null` if no error), second argument is boolean, that is `true` if collection exists and `false` if not. `collectionExists` function can also be implemented with promises instead of callbacks. – weekens Jul 09 '18 at 12:33
  • I already have same info with listCollections().toArray . I need to write simple function like : isExist (name ) , and use it like if ( isExist('mycollection') == true) { doSomething(); } Maybe i will need async methods... – Nikola Lukic Jul 09 '18 at 14:30
  • 1
    @NikolaLukic, yes, you will probably end up with `if (await isExist('mycollection'))` or `if (yield isExist('mycollection'))`. There is no other way to make asynchronous method look like synchronous one. I guess, `== true` is redundant. – weekens Jul 10 '18 at 16:49
5

If you use mongodb 3.1.10. This is how to check if collections exist.

MongoClient.connect(url, { useNewUrlParser: true }, function(err, client) {
  if (err) throw err;

  var dbo = client.db("dbname");
  dbo.listCollections().toArray(function(err, items){
    if (err) throw err;

    console.log(items); 
    if (items.length == 0)
        console.log("No collections in database")  
  }); 
});
roscoe_x
  • 609
  • 1
  • 9
  • 16
3

actually, this works for me

  await db.createCollection(name, function (err, res) {
    if (err) {
        //console.log(err);
        if (err.codeName =="NamespaceExists") {
            console.log("Already Exists Collection  : " + name + "");
            return;
        }
    }
    console.log("Collection created! : "+name+"");

});
BugsCreator
  • 433
  • 3
  • 10
3

An async TypeScript function:

/**
 * Predicate function that checks if a collection exists in a given MongoDB database
 *
 * @param {Db} db Mongo database instance
 * @param {string} collectionName Name of collection
 *
 * @returns {boolean} true if collection exists, false otherwise
 */
export const doesCollectionExist = async (db: Db, collectionName: string): Promise<boolean> => {
  const cursor = db.listCollections({ name: collectionName })
  const result = await cursor.hasNext()
  await cursor.close()

  return result
}
BigMan73
  • 1,344
  • 15
  • 14
2

An updated answer which works with 3.6.* releases.

/**
 * Checks if a collection exists in a mongo database.
 * 
 * @param db a mongo db object.  eg.
 *    client = await MongoClient.connect(uri);
 *    db = client.db();
 * @param collectionName the name of the collection to search for
 * @returns {Promise<boolean>}
 */
async function doesCollectionExistInDb(db, collectionName) {
  const collections = await db.collections();
  return collections.some(
      (collection) => collection.collectionName === collectionName
  );
}

...

if (await doesCollectionExistInDb(db, 'products')) {
   // Do something, such as create a new collection
}

The collection.collectionName is part of the documented collection api as can be found here: http://mongodb.github.io/node-mongodb-native/3.6/api/Collection.html#collectionName

MattCochrane
  • 2,900
  • 2
  • 25
  • 35
2

For nodejs with mongodb library (v 3.6.3) that's the only way I got it working:

const collectionName = 'products'
const exists = (await (await db.listCollections().toArray()).findIndex((item) => item.name === collectionName) !== -1)
console.log(exists)

Hope that helps others

Lincoln
  • 880
  • 14
  • 25
1

The question refers to the native driver, but I got here searching how to do this in pymongo. Usually pymongo's api is identical to the JS api, but in this case collection_names doesn't have an argument for the collection's name (as in JohnnyHK's answer), but rather the first argument is a boolean (whether to include system collections). Since a string evaluates to True, this can be confusing. So I hope this helps future readers:

import pymongo

cl = pymongo.MongoClient()
db = cl['my-db']
if 'my-col' in db.collection_names(False):
   ...
Community
  • 1
  • 1
dimid
  • 7,285
  • 1
  • 46
  • 85
0
/* set database */
let db          = client.db( 'crud' )

/* set collection */
let collection  = db.collection( 'categories' )

/* set query */
collection.find( {} ).toArray( ( err, result ) => {

if ( result.length > 0 )
{
    console.log("Exist");
}
else
{
    console.log("Not Exist");

    // create collection
}

}

antelove
  • 3,216
  • 26
  • 20