using MongoDB.Driver; using MongoDB.Driver.Linq; using MongoDbGenericRepository.DataAccess.Base; using MongoDbGenericRepository.Models; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; namespace MongoDbGenericRepository.DataAccess.Read { /// /// A class to read MongoDb document. /// public partial class MongoDbReader : DataAccessBase { /// /// The construct of the MongoDbReader class. /// /// A instance. public MongoDbReader(IMongoDbContext mongoDbContext) : base(mongoDbContext) { } #region Read TKey /// /// Asynchronously returns one document given its id. /// /// The type representing a Document. /// The type of the primary key for a Document. /// The Id of the document you want to get. /// An optional partition key. /// An optional cancellation Token. public virtual async Task GetByIdAsync(TKey id, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { var filter = Builders.Filter.Eq("Id", id); return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(cancellationToken); } /// /// Returns one document given its id. /// /// The type representing a Document. /// The type of the primary key for a Document. /// The Id of the document you want to get. /// An optional partition key. public virtual TDocument GetById(TKey id, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { var filter = Builders.Filter.Eq("Id", id); return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); } /// /// Asynchronously returns one document given filter definition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A mongodb filter definition. /// A mongodb filter option. /// An optional partition key. /// An optional cancellation Token. public virtual Task GetOneAsync(FilterDefinition condition, FindOptions findOption = null, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(condition, findOption).FirstOrDefaultAsync(cancellationToken); } /// /// Returns one document given filter definition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A mongodb filter definition. /// A mongodb filter option. /// An optional partition key. public virtual TDocument GetOne(FilterDefinition condition, FindOptions findOption = null, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(condition, findOption).FirstOrDefault(); } /// /// Asynchronously returns one document given an expression filter. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// An optional partition key. /// An optional cancellation Token. public virtual async Task GetOneAsync(Expression> filter, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return await HandlePartitioned(partitionKey).Find(filter).FirstOrDefaultAsync(cancellationToken); } /// /// Returns one document given an expression filter. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// An optional partition key. public virtual TDocument GetOne(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(filter).FirstOrDefault(); } /// /// Returns a collection cursor. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// An optional partition key. public virtual IFindFluent GetCursor(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(filter); } /// /// Returns true if any of the document of the collection matches the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A mongodb filter definition. /// A mongodb counting option. /// An optional partition key. /// An optional cancellation Token. public virtual async Task AnyAsync(FilterDefinition condition, CountOptions countOption = null, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { var count = await HandlePartitioned(partitionKey).CountDocumentsAsync(condition, countOption, cancellationToken); return count > 0; } /// /// Returns true if any of the document of the collection matches the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A mongodb filter definition. /// A mongodb counting option. /// An optional partition key. public virtual bool Any(FilterDefinition condition, CountOptions countOption = null, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { var count = HandlePartitioned(partitionKey).CountDocuments(condition, countOption); return count > 0; } /// /// Returns true if any of the document of the collection matches the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// An optional partition key. /// An optional cancellation Token. public virtual async Task AnyAsync(Expression> filter, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { var count = await HandlePartitioned(partitionKey).CountDocumentsAsync(filter, cancellationToken: cancellationToken); return (count > 0); } /// /// Returns true if any of the document of the collection matches the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// An optional partition key. public virtual bool Any(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { var count = HandlePartitioned(partitionKey).CountDocuments(filter); return (count > 0); } /// /// Asynchronously returns a list of the documents matching the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A mongodb filter definition. /// A mongodb filter option. /// An optional partition key. /// An optional cancellation Token. public virtual Task> GetAllAsync(FilterDefinition condition, FindOptions findOption = null, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(condition, findOption).ToListAsync(cancellationToken); } /// /// Returns a list of the documents matching the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A mongodb filter definition. /// A mongodb filter option. /// An optional partition key. public virtual List GetAll(FilterDefinition condition, FindOptions findOption = null, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(condition, findOption).ToList(); } /// /// Asynchronously returns a list of the documents matching the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// An optional partition key. /// An optional cancellation Token. public virtual async Task> GetAllAsync(Expression> filter, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return await HandlePartitioned(partitionKey).Find(filter).ToListAsync(cancellationToken); } /// /// Returns a list of the documents matching the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// An optional partition key. public virtual List GetAll(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(filter).ToList(); } /// /// Asynchronously counts how many documents match the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A mongodb filter definition. /// A mongodb counting option. /// An optional partitionKey /// An optional cancellation Token. public virtual Task CountAsync(FilterDefinition condition, CountOptions countOption = null, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return HandlePartitioned(partitionKey).CountDocumentsAsync(condition, countOption, cancellationToken); } /// /// Counts how many documents match the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A mongodb filter definition. /// A mongodb counting option. /// An optional partitionKey public virtual long Count(FilterDefinition condition, CountOptions countOption = null, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return HandlePartitioned(partitionKey).CountDocuments(condition, countOption); } /// /// Asynchronously counts how many documents match the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// An optional partitionKey /// An optional cancellation Token. public virtual async Task CountAsync(Expression> filter, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return await HandlePartitioned(partitionKey).CountDocumentsAsync(filter, cancellationToken: cancellationToken); } /// /// Counts how many documents match the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// An optional partitionKey public virtual long Count(Expression> filter, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return HandlePartitioned(partitionKey).Find(filter).CountDocuments(); } #endregion #region Min / Max /// /// Gets the document with the maximum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by descending. /// An optional partitionKey. /// An optional cancellation Token. public virtual async Task GetByMaxAsync(Expression> filter, Expression> maxValueSelector, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return await GetCollection(partitionKey).Find(Builders.Filter.Where(filter)) .SortByDescending(maxValueSelector) .Limit(1) .FirstOrDefaultAsync(cancellationToken); } /// /// Gets the document with the maximum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by descending. /// An optional partitionKey. public virtual TDocument GetByMax(Expression> filter, Expression> maxValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return GetCollection(partitionKey).Find(Builders.Filter.Where(filter)) .SortByDescending(maxValueSelector) .Limit(1) .FirstOrDefault(); } /// /// Gets the document with the minimum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. /// An optional cancellation Token. public virtual async Task GetByMinAsync(Expression> filter, Expression> minValueSelector, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return await GetCollection(partitionKey).Find(Builders.Filter.Where(filter)) .SortBy(minValueSelector) .Limit(1) .FirstOrDefaultAsync(cancellationToken); } /// /// Gets the document with the minimum value of a specified property in a MongoDB collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. public virtual TDocument GetByMin(Expression> filter, Expression> minValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return GetCollection(partitionKey).Find(Builders.Filter.Where(filter)) .SortBy(minValueSelector) .Limit(1) .FirstOrDefault(); } /// /// Gets the maximum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the field for which you want the maximum value. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. /// An optional cancellation Token. public virtual async Task GetMaxValueAsync(Expression> filter, Expression> maxValueSelector, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return await GetMaxMongoQuery(filter, maxValueSelector, partitionKey) .Project(maxValueSelector) .FirstOrDefaultAsync(cancellationToken); } /// /// Gets the maximum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the value used to order the query. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partitionKey. public virtual TValue GetMaxValue(Expression> filter, Expression> maxValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return GetMaxMongoQuery(filter, maxValueSelector, partitionKey) .Project(maxValueSelector) .FirstOrDefault(); } /// /// Gets the minimum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the value used to order the query. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partition key. /// An optional cancellation Token. public virtual async Task GetMinValueAsync(Expression> filter, Expression> minValueSelector, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return await GetMinMongoQuery(filter, minValueSelector, partitionKey).Project(minValueSelector).FirstOrDefaultAsync(cancellationToken); } /// /// Gets the minimum value of a property in a mongodb collections that is satisfying the filter. /// /// The document type. /// The type of the primary key. /// The type of the value used to order the query. /// A LINQ expression filter. /// A property selector to order by ascending. /// An optional partition key. public virtual TValue GetMinValue(Expression> filter, Expression> minValueSelector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return GetMinMongoQuery(filter, minValueSelector, partitionKey).Project(minValueSelector).FirstOrDefault(); } #endregion Min / Max #region Sum TKey /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. /// An optional cancellation Token. public virtual async Task SumByAsync(Expression> filter, Expression> selector, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return await GetQuery(filter, partitionKey).SumAsync(selector, cancellationToken); } /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. public virtual int SumBy(Expression> filter, Expression> selector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return GetQuery(filter, partitionKey).Sum(selector); } /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. /// An optional cancellation Token. public virtual async Task SumByAsync(Expression> filter, Expression> selector, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return await GetQuery(filter, partitionKey).SumAsync(selector, cancellationToken); } /// /// Sums the values of a selected field for a given filtered collection of documents. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// The field you want to sum. /// The partition key of your document, if any. public virtual decimal SumBy(Expression> filter, Expression> selector, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable { return GetQuery(filter, partitionKey).Sum(selector); } #endregion Sum TKey } public partial class MongoDbReader { /// /// Groups a collection of documents given a grouping criteria, /// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. /// /// The type representing a Document. /// The type of the primary key for a Document. /// The type of the grouping criteria. /// The type of the projected group. /// The grouping criteria. /// The projected group result. /// The partition key of your document, if any. public virtual List GroupBy( Expression> groupingCriteria, Expression, TProjection>> groupProjection, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable where TProjection : class, new() { return HandlePartitioned(partitionKey) .Aggregate() .Group(groupingCriteria, groupProjection) .ToList(); } /// /// Groups filtered a collection of documents given a grouping criteria, /// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. /// /// The type representing a Document. /// The type of the primary key for a Document. /// The type of the grouping criteria. /// The type of the projected group. /// A LINQ expression filter. /// The grouping criteria. /// The projected group result. /// The partition key of your document, if any. public virtual List GroupBy( Expression> filter, Expression> selector, Expression, TProjection>> projection, string partitionKey = null) where TDocument : IDocument where TKey : IEquatable where TProjection : class, new() { var collection = HandlePartitioned(partitionKey); return collection.Aggregate() .Match(Builders.Filter.Where(filter)) .Group(selector, projection) .ToList(); } /// /// Groups filtered a collection of documents given a grouping criteria, /// and returns a dictionary of listed document groups with keys having the different values of the grouping criteria. /// /// The type representing a Document. /// The type of the primary key for a Document. /// The type of the grouping criteria. /// The type of the projected group. /// A LINQ expression filter. /// The grouping criteria. /// The projected group result. /// The partition key of your document, if any. /// An optional cancellation Token. public virtual async Task> GroupByAsync( Expression> filter, Expression> selector, Expression, TProjection>> projection, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable where TProjection : class, new() { var collection = HandlePartitioned(partitionKey); return await collection.Aggregate() .Match(Builders.Filter.Where(filter)) .Group(selector, projection) .ToListAsync(cancellationToken); } /// /// Asynchronously returns a paginated list of the documents matching the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// The property selector. /// Order of the sorting. /// The number of documents you want to skip. Default value is 0. /// The number of documents you want to take. Default value is 50. /// An optional partition key. /// An optional cancellation Token. public virtual async Task> GetSortedPaginatedAsync( Expression> filter, Expression> sortSelector, bool ascending = true, int skipNumber = 0, int takeNumber = 50, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { var sorting = ascending ? Builders.Sort.Ascending(sortSelector) : Builders.Sort.Descending(sortSelector); return await HandlePartitioned(partitionKey) .Find(filter) .Sort(sorting) .Skip(skipNumber) .Limit(takeNumber) .ToListAsync(cancellationToken); } /// /// Asynchronously returns a paginated list of the documents matching the filter condition. /// /// The type representing a Document. /// The type of the primary key for a Document. /// A LINQ expression filter. /// The sort definition. /// The number of documents you want to skip. Default value is 0. /// The number of documents you want to take. Default value is 50. /// An optional partition key. /// An optional cancellation Token. public virtual async Task> GetSortedPaginatedAsync( Expression> filter, SortDefinition sortDefinition, int skipNumber = 0, int takeNumber = 50, string partitionKey = null, CancellationToken cancellationToken = default) where TDocument : IDocument where TKey : IEquatable { return await HandlePartitioned(partitionKey) .Find(filter) .Sort(sortDefinition) .Skip(skipNumber) .Limit(takeNumber) .ToListAsync(cancellationToken); } } }