61

Is there a command that i can use via javascript in mongo shell that can be used to check if the particular index exists in my mongodb. I am building a script file that would create indexes. I would like that if I run this file multiple number of times then the indexes that already exists are not recreated.

I can use db.collection.getIndexes() to get the collection of all the indexes in my db and then build a logic to ignore the ones that already exists but i was wondering if there is command to get an index and then ignore a script that creates the index. Something like:

If !exists(db.collection.exists("indexname")) 
{
    create  db.collectionName.CreateIndex("IndexName")
}
CSC
  • 1,175
  • 3
  • 11
  • 24
  • 10
    Calling `createIndex` when the index already exists is a no-op, so there's really no need to check. – JohnnyHK Jan 26 '16 at 17:08
  • 1
    Possible duplicate of [ensureIndex in mongodb](http://stackoverflow.com/questions/12547526/ensureindex-in-mongodb) – BatScream Jan 26 '16 at 18:59
  • 1
    @JohnnyHK: it's not a no-op if you don't have write permissions. In that case, the code will throw an error `not authorized to execute command { insert: "system.indexes" ...`, instead of failing silently. – Dan Dascalescu May 09 '19 at 20:43

7 Answers7

84

Creating indexes in MongoDB is an idempotent operation. So running db.names.createIndex({name:1}) would create the index only if it didn't already exist.

The deprecated (as of MongoDB 3.0) alias for createIndex() is ensureIndex() which is a bit clearer on what createIndex() actually does.


Edit: Thanks to ZitRo for clarifying in comments that calling createIndex() with the same name but different options than an existing index will throw an error MongoError: Index with name: **indexName** already exists with different options as explained in this question.


If you have other reasons for checking, then you can access current index data one of two ways:

  1. As of v3.0, we can use db.names.getIndexes() where names is the name of the collection. Docs here.
  2. Before v3.0, you can access the system.indexes collection and do a find as bri describes below.
Community
  • 1
  • 1
metame
  • 2,480
  • 1
  • 17
  • 22
  • 6
    Note that we may catch `MongoError: Index with name: **indexName** already exists with different options` error by doing just `createIndex`. So using `db.collection.getIndexes()` make sense sometimes. See [this question](http://stackoverflow.com/q/30232081/2590150) for more info. – ZitRo May 06 '17 at 12:10
  • This answer is surprising. I came here because `createIndex` is taking upward of 30 seconds on every boot of my server (mongo 2.6). Surely it doesn't take that long to confirm whether or not the index exists? – Vala Jul 05 '17 at 09:54
  • @Thor84no 2.6 doesn't use `createIndex`, it uses `ensureIndex` https://docs.mongodb.com/v2.6/core/index-creation/ – metame Jul 05 '17 at 13:56
  • Either way, it's taking ages and restarting the server it's no quicker. It also makes no sense that verifying the existence of the index is taking longer on my large collections than on my small ones... – Vala Jul 05 '17 at 15:57
  • @Thor84no sounds like you may want to ask a question yourself :) – metame Jul 05 '17 at 16:19
  • 2
    I found that `collection.createIndex(DBObject("_ts" -> 1), DBObject("expireAfterSeconds" -> ttl))` is not idempotent - if the expiration value is different than what's already in use, it will fail. Perhaps that's a special case that this MongoDB noob stumbled across, though. – Don Branson Feb 07 '18 at 21:11
  • `.createIndex` is also not idempotent if you don't have write permissions. In that case, the code will throw an error `not authorized to execute command { insert: "system.indexes" ...`, instead of just not (re)creating the index. – Dan Dascalescu May 09 '19 at 20:44
21

Use db.system.indexes and search on it.

If, for example, you have an index called 'indexname', you can search for it like this:

db.system.indexes.find({'name':'indexname'});

If you need to search for that index on a specific collection,then you need to use the ns property (and, it would be helpful to have the db name).

db.system.indexes.find({'name':'indexname', 'ns':'dbname.collection'});

Or, if you absolutely hate including the db name...

db.system.indexes.find({'name':'indexname', 'ns': {$regex:'.collection$'}});

Pulling that together...

So, you're finished check would be:

if(db.system.indexes.find({name:'indexname',ns:{$regex:'.collection$'}}).count()==0) { 
    db.collection.createIndex({blah:1},{name:'indexname'}) 
}
bri
  • 2,932
  • 16
  • 17
  • Does this work on 3.4 version. I tried but it returns nothing on the console. –  May 05 '17 at 04:52
  • 3
    @SohamShetty This has been deprecated as of v3.0. You now should use `db.name.getIndexes()` where `name` is the name of your collection. – metame May 06 '17 at 12:35
2

Using nodeJS MongoDB driver version 2.2:


const MongoClient = require('mongodb').MongoClient;

exports.dropOldIndexIfExist = dropOldIndexIfExist;
async function dropOldIndexIfExist() {
  try {
    const mongoConnection = MongoClient.connect('mongodb://localhost:27017/test');
    const indexName = 'name_1';
    const isIndexExist = await mongoConnection.indexExists(indexName);
    if (isIndexExist === true) {
      await mongoConnection.dropIndex(indexName);
    }
  } catch (err) {
    console.error('dropOldIndexIfExist', err.message);
    throw err;
  }
}
Dvir Arad
  • 147
  • 1
  • 9
2

I've created a custom method in c# to check if the index exists, using mongo driver:

public bool IndexExists<TDocument>(
    IMongoCollection<TDocument> collection, string name)
{
    var indexes = collection.Indexes.List().ToList();
    var indexNames = indexes
        .SelectMany(index => index.Elements)
        .Where(element => element.Name == "name")
        .Select(name => name.Value.ToString());
    
    return indexNames.Contains(name);
}
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Sérgio Bueno
  • 99
  • 1
  • 3
1

maybe we can use something like https://docs.mongodb.com/v3.2/reference/method/db.collection.getIndexes/#db.collection.getIndexes to check if the collection have an index equal to something ?

if yes then drop and add the new one or add the new one directly

ctf0
  • 6,991
  • 5
  • 37
  • 46
1

In my case i did as follows.

   DBCollection yourcollectionName = mt.getCollection("your_collection");
    if (yourcollectionName.getIndexInfo() == null || yourcollectionName.getIndexInfo().isEmpty()) {         
      DBObject indexOptions = new BasicDBObject();
      indexOptions.put("pro1", 1);
      indexOptions.put("pro2", 1);       
      yourcollectionName.createIndex(indexOptions, "name_of_your_index", true);
     }
Ramesh Papaganti
  • 7,311
  • 3
  • 31
  • 36
0

Here is a Python 3.5+ and pymongo >= 4.1 (type hints) function that I wrote which checks to see if the index name exists (other details about the index are omitted).

from pymongo import MongoClient
from pymongo.collection import Collection

def check_collection_indexes(db: MongoClient, collection_name: str, index_name: str) -> bool:
    coll: Collection = db[collection_name]
    indexes: dict = coll.index_information()
    
    # assume false
    found = False
    # get length of the index name for substring
    l = len(index_name)
    for k in indexes.keys():
        # Substring the keys and check for match
        if k[:l] == index_name:
            found = True
            break
        else:
            found = False
    return found

If the index exists it will return True, otherwise you can use the False output to call another function that creates/recreates the indexes.

A Webb
  • 633
  • 1
  • 8
  • 16