Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to create or update a MongoDB index?

According to the documentation on the createIndexes command:

If you create an index with one set of options and then issue createIndexes with the same index fields but different options, MongoDB will not change the options nor rebuild the index.

The solution is to drop the index and create it from scratch, but that's costly.

Is there a way to create an index when there isn't one, do nothing if there is an index with the same options, and replace the index if the options have changed?


This question was originally raised by Phil Barresi here but has since been deleted.

like image 777
i3arnon Avatar asked Oct 31 '22 20:10

i3arnon


1 Answers

Looking at the driver I've implemented a CreateOrUpdateIndex extension method that compares the raw index documents and if the index options have changed the index is replaced (as long as the index name stays the same):

public static WriteConcernResult CreateOrUpdateIndex(
    this MongoCollection mongoCollection,
    IMongoIndexKeys keys,
    IMongoIndexOptions options = null)
{
    if (mongoCollection.IndexExists(keys))
    {
        var indexDocument = mongoCollection.GenerateIndexDocument(keys, options);
        if (!mongoCollection.GetIndexes().RawDocuments.Any(indexDocument.Equals))
        {
            mongoCollection.DropIndex(keys);
        }
    }

    return mongoCollection.CreateIndex(keys, options);
}

Generating the raw index document:

public static BsonDocument GenerateIndexDocument(this MongoCollection mongoCollection, IMongoIndexKeys keys, IMongoIndexOptions options)
{
    var optionsDocument = options.ToBsonDocument();
    var keysDocument = keys.ToBsonDocument();
    var indexDocument = new BsonDocument
    {
        { "ns", mongoCollection.FullName },
        { "name", GenerateIndexName(keysDocument, optionsDocument) },
        { "key", keysDocument }
    };
    if (optionsDocument != null)
    {
        indexDocument.Merge(optionsDocument);
    }

    return indexDocument;
}

public static string GenerateIndexName(IEnumerable<BsonElement> keys, BsonDocument options)
{
    const string name = "name";
    if (options != null && options.Contains(name)) return options[name].AsString;

    return string.Join("_", keys.Select(element =>
    {
        var value = "x";
        switch (element.Value.BsonType)
        {
            case BsonType.Int32: value = ((BsonInt32)element.Value).Value.ToString(); break;
            case BsonType.Int64: value = ((BsonInt64)element.Value).Value.ToString(); break;
            case BsonType.Double: value = ((BsonDouble)element.Value).Value.ToString(); break;
            case BsonType.String: value = ((BsonString)element.Value).Value; break;
        }
        return string.Format("{0}_{1}", element.Name, value.Replace(' ', '_'));
    }));
}
like image 190
i3arnon Avatar answered Nov 09 '22 22:11

i3arnon