diff --git a/MongoDbGenericRepository/BaseMongoDbRepository.cs b/MongoDbGenericRepository/BaseMongoDbRepository.cs index c59b08e..b39c3de 100644 --- a/MongoDbGenericRepository/BaseMongoDbRepository.cs +++ b/MongoDbGenericRepository/BaseMongoDbRepository.cs @@ -230,7 +230,6 @@ namespace MongoDbGenericRepository } } - #endregion #region Update @@ -1082,6 +1081,177 @@ namespace MongoDbGenericRepository #endregion Find And Update + #region Index Management + + /// + /// Create an Index given a field and an optional ascending / descending parameter + /// we want to create them in the background as we want the db to still be available during this process + /// + /// + /// The field we want to index + /// Options for creating an index.. + /// An optional partition key + /// The result of the create index operation. + public async Task CreateTextIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) + where TDocument : IDocument + { + return await HandlePartitioned(partitionKey).Indexes + .CreateOneAsync( + new CreateIndexModel( + Builders.IndexKeys.Text(field), + indexCreationOptions == null ? null : MapIndexOptions(indexCreationOptions) + )); + } + + private CreateIndexOptions MapIndexOptions(IndexCreationOptions indexCreationOptions) + { + return new CreateIndexOptions + { + Unique = indexCreationOptions.Unique, + TextIndexVersion = indexCreationOptions.TextIndexVersion, + SphereIndexVersion = indexCreationOptions.SphereIndexVersion, + Sparse = indexCreationOptions.Sparse, + Name = indexCreationOptions.Name, + Min = indexCreationOptions.Min, + Max = indexCreationOptions.Max, + LanguageOverride = indexCreationOptions.LanguageOverride, + ExpireAfter = indexCreationOptions.ExpireAfter, + DefaultLanguage = indexCreationOptions.DefaultLanguage, + BucketSize = indexCreationOptions.BucketSize, + Bits = indexCreationOptions.Bits, + Background = indexCreationOptions.Background, + Version = indexCreationOptions.Version + }; + } + + /// + /// Creates an index on the given field in ascending order + /// + /// + /// The field we want to index + /// Options for creating an index.. + /// An optional partition key + /// + public async Task CreateAscendingIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) where TDocument : IDocument + { + var collection = HandlePartitioned(partitionKey); + var createOptions = indexCreationOptions == null ? null : MapIndexOptions(indexCreationOptions); + var indexKey = Builders.IndexKeys; + return await collection.Indexes + .CreateOneAsync( + new CreateIndexModel(indexKey.Ascending(field), createOptions)); + } + + /// + /// Creates an index on the given field in ascending order + /// + /// + /// The field we want to index + /// Options for creating an index.. + /// An optional partition key + /// + public async Task CreateDescendingIndexAsync(Expression> field, IndexCreationOptions indexCreationOptions = null, string partitionKey = null) where TDocument : IDocument + { + var collection = HandlePartitioned(partitionKey); + var createOptions = indexCreationOptions == null ? null : MapIndexOptions(indexCreationOptions); + var indexKey = Builders.IndexKeys; + return await collection.Indexes + .CreateOneAsync( + new CreateIndexModel(indexKey.Descending(field), createOptions)); + } + + /// + /// Create an Index given a field and an optional ascending / descending parameter + /// + /// + /// + /// + /// + public async Task CreateHshedIndexAsync(Expression> field) + where TDocument : IDocument + { + var collection = HandlePartitioned(partitionKey); + var createOptions = new CreateIndexOptions + { + Background = createInBackGround + }; + var indexKey = Builders.IndexKeys; + if (ascending) + { + return await collection.Indexes + .CreateOneAsync( + new CreateIndexModel(indexKey.Ascending(field), createOptions)); + } + else + { + return await collection.Indexes + .CreateOneAsync( + new CreateIndexModel(indexKey.Descending(field), createOptions)); + } + // we want to create them in the background as we want the db to still be available during this process + var collection = GetCollection(); + var indexKey = Builders.IndexKeys; + switch (mongoCollectionIndexType) + { + case MongoCollectionIndexType.Text: + return await collection.Indexes.CreateOneAsync(indexKey.Text(field), new CreateIndexOptions { Background = true }); + case MongoCollectionIndexType.Hashed: + return await collection.Indexes.CreateOneAsync(indexKey.Hashed(field), new CreateIndexOptions { Background = true }); + default: + return await collection.Indexes.CreateOneAsync(indexKey.Hashed(field), new CreateIndexOptions { Background = true }); + } + } + + + /// + /// We are only allowed one Text index per MongoCollection, this method will combine Text indexes across multiple string fields + /// + /// + /// + /// + public async Task CreateCombinedTextIndexAsync(params Expression>[] fields) where T : BaseMongoEntity + { + var collection = GetCollection(); + var listOfDefs = new List>(); + foreach (var field in fields) + { + listOfDefs.Add(Builders.IndexKeys.Text(field)); + } + return await collection.Indexes.CreateOneAsync(Builders.IndexKeys.Combine(listOfDefs), new CreateIndexOptions + { + Background = true // we want to create them in the background as we want the db to still be available + }); + } + + /// + /// Drops the index given a field name + /// + /// + /// + /// + public async Task DropIndexAsync(string fieldName) where T : BaseMongoEntity + { + var collection = GetCollection(); + await collection.Indexes.DropOneAsync(fieldName); + } + + /// + /// Drops the index given a field name + /// + /// + /// + public async Task> GetIndexesNamesAsync() where T : BaseMongoEntity + { + var collection = GetCollection(); + var indexCursor = await collection.Indexes.ListAsync(); + var indexes = await indexCursor.ToListAsync(); + var values = indexes.Select(e => e["name"].ToString()).ToList(); + return values; + } + + + #endregion Index Management + /// /// Sets the value of the document Id if it is not set already. /// diff --git a/MongoDbGenericRepository/Models/IndexCreationOptions.cs b/MongoDbGenericRepository/Models/IndexCreationOptions.cs new file mode 100644 index 0000000..a117b2a --- /dev/null +++ b/MongoDbGenericRepository/Models/IndexCreationOptions.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MongoDbGenericRepository.Models +{ + /// + /// Options for creating an index. + /// + public class IndexCreationOptions + { + /// + /// Gets or sets a value indicating whether the index is a unique index. + /// + public bool? Unique { get; set; } + /// + /// Gets or sets the index version for text indexes. + /// + public int? TextIndexVersion { get; set; } + /// + /// Gets or sets the index version for 2dsphere indexes. + /// + public int? SphereIndexVersion { get; set; } + /// + /// Gets or sets a value indicating whether the index is a sparse index. + /// + public bool? Sparse { get; set; } + /// + /// Gets or sets the index name. + /// + public string Name { get; set; } + /// + /// Gets or sets the min value for 2d indexes. + /// + public double? Min { get; set; } + /// + /// Gets or sets the max value for 2d indexes. + /// + public double? Max { get; set; } + /// + /// Gets or sets the language override. + /// + public string LanguageOverride { get; set; } + /// + /// Gets or sets when documents expire (used with TTL indexes). + /// + public TimeSpan? ExpireAfter { get; set; } + /// + /// Gets or sets the default language. + /// + public string DefaultLanguage { get; set; } + /// + /// Gets or sets the size of a geohash bucket. + /// + public double? BucketSize { get; set; } + /// + /// Gets or sets the precision, in bits, used with geohash indexes. + /// + public int? Bits { get; set; } + /// + /// Gets or sets a value indicating whether to create the index in the background. + /// + public bool? Background { get; set; } + /// + /// Gets or sets the version of the index. + /// + public int? Version { get; set; } + } +}