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.
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(' ', '_'));
}));
}
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