alexandre-spieser / mongodb-generic-repository

An example of generic repository implementation using the MongoDB C# Sharp 2.0 driver (async)
MIT License
315 stars 87 forks source link

Get Sum Value [HELP WANTED] #10

Closed orochasamuel closed 5 years ago

orochasamuel commented 5 years ago

Hi @alexandre-spieser

I manage customer stock and would like to know how I get the sum of the quantities in the collection. Here is a more or less example:

My Class


public class StockMovement : Document
    {
        public StockMovement()
        {
            Version = 1;
        }

        public Tenant Tenant { get; set; }
        public Company Company { get; set; }
        public Stock Stock { get; set; }
        public Product Product { get; set; }

        /// <summary>
        /// Entry, // Purchase
        /// Departure // Orders
        /// </summary>
        [BsonRequired]
        public Type MovementType { get; set; }

        /// <summary>
        /// My Quatity is NEGATIVE for MovementType "Departure" Sales/Orders for customers
        /// </summary>
        [BsonRepresentation(BsonType.Decimal128)]
        public decimal Quantity { get; set; }

        /// <summary>
        /// My UnitaryValue is NEGATIVE for MovementType "Departure" Sales/Orders for customers
        /// </summary>
        [BsonRepresentation(BsonType.Decimal128)]
        public decimal UnitaryValue { get; set; }

        public string Observation { get; set; }

        public User AddedBy { get; set; }
        public DateTime UpdatedAtUtc { get; set; }
        public User UpdatedBy { get; set; }
        public DateTime DeletedAtUtc { get; set; }
        public User DeletedBy { get; set; }
    }

My Service


public decimal GetQuantityByProductInStock(Guid productId, Guid companyId, Guid tenantId)
        {
            //Useless
            //var currentProduct = _repo.GetById<Product>(produtoId);

            var quantityInStock = _repo.GetAll<StockMovement>(w =>
                    w.Tenant.Id == tenantId && w.Company.Id == companyId && w.Product.Id == productId)
                .Sum(s => s.Quantity);

            if (quantityInStock <= 0)
                throw new Exception($@"NO stock :(");

            return quantityInStock;
        }

To get the result is done the sum of all the moves but, the customer already has more than 20k entries. How can I improve this?

I considered using asynchronous but, I do not know very well. Is it the only way out?

Can you help me please?

alexandre-spieser commented 5 years ago

Try this:

        /// <summary>
        /// Sums the values of a selected field for a given filtered collection of documents.
        /// </summary>
        /// <typeparam name="TDocument">The type representing a Document.</typeparam>
        /// <param name = "filter" > A LINQ expression filter.</param>
        /// <param name="selector">The field you want to sum.</param>
        /// <param name="partitionKey">The partition key of your document, if any.</param>
        public virtual async Task<decimal> SumByAsync<TDocument>(Expression<Func<TDocument, bool>> filter,
                                                       Expression<Func<TDocument, decimal>> selector,
                                                       string partitionKey = null)
                                                       where TDocument : IDocument
        {
            var collection = string.IsNullOrEmpty(partitionKey) ? GetCollection<TDocument>() : GetCollection<TDocument>(partitionKey);

            return await collection.AsQueryable()
                                   .Where(filter)
                                   .SumAsync(selector);
        }