// ..................................................................................Get Product Filters..................................................................... public async Task <Filters> GetProductFilters(IEnumerable <QueryResult> products, QueryParams queryParams) { Filters filters = new Filters(); List <int> productIds = products.Select(x => x.Id).ToList(); var avgWeight = products.Select(x => x.Weight).Sum() / products.Count(); // Grab niche info from the products var niches = products .GroupBy(x => x.NicheId, (key, x) => new { nicheId = key, weight = x.Sum(z => z.Weight) / x.Count(), productCount = x.Count() }).ToList(); // Get categories based on niche ids var categories = await context.Niches .AsNoTracking() .Where(x => niches.Select(x => x.nicheId).ToList() .Contains(x.Id)) .Select(x => new { nicheId = x.Id, nicheName = x.Name, nicheUrlid = x.UrlId, nicheUrlName = x.UrlName, categoryId = x.CategoryId, categoryName = x.Category.Name, categoryUrlId = x.Category.UrlId, categoryUrlName = x.Category.UrlName }) .ToListAsync(); // Join the categories and niches together var categoryData = categories.Join(niches, x => x.nicheId, x => x.nicheId, (categories, niches) => new { categories.nicheId, categories.nicheName, categories.nicheUrlid, categories.nicheUrlName, categories.categoryId, categories.categoryName, categories.categoryUrlId, categories.categoryUrlName, niches.weight, niches.productCount }) // Group the categories together by category id .GroupBy(x => x.categoryId, (key, x) => new { categoryId = key, categoryName = x.Select(z => z.categoryName).FirstOrDefault(), categoryUrlId = x.Select(z => z.categoryUrlId).FirstOrDefault(), categoryUrlName = x.Select(z => z.categoryUrlName).FirstOrDefault(), niches = x.Select(z => new { z.nicheId, z.nicheName, z.nicheUrlid, z.nicheUrlName, z.weight, z.productCount }).ToList() }) // This will add a weight to each category and order the niches by weight .Select(x => new { weight = x.niches.Select(z => z.productCount * z.weight).Sum() / x.niches.Select(z => z.productCount).Sum(), x.categoryUrlId, x.categoryUrlName, x.categoryName, niches = x.niches .OrderByDescending(z => z.weight) // group the niches by weight greater or equal to the average weight .GroupBy(z => z.weight >= avgWeight, (key, niches) => new { key, niches = niches.Select(n => new { UrlId = n.nicheUrlid, UrlName = n.nicheUrlName, Name = n.nicheName, }).ToList() }).ToList() }) // Order the categories by weight and group by weight greater or equal to the average weight .OrderByDescending(x => x.weight) .GroupBy(x => x.weight >= avgWeight, (key, categories) => new { key, categories = categories.Select(z => new { UrlId = z.categoryUrlId, UrlName = z.categoryUrlName, Name = z.categoryName, Niches = z.niches, }).ToList() }) .ToList(); // Assign the category filters if (categoryData.Count == 2) { filters.CategoriesFilter = new CategoriesFilter { Visible = categoryData.Where(x => x.key).Select(x => x.categories .Select(z => new CategoryFilter { UrlId = z.UrlId, UrlName = z.UrlName, Name = z.Name, Niches = new NichesFilter { ShowHidden = false, Visible = z.Niches.Where(w => w.key).Select(n => n.niches.Select(a => new NicheFilter { UrlId = a.UrlId, UrlName = a.UrlName, Name = a.Name }).ToList()).SingleOrDefault(), Hidden = z.Niches.Where(w => !w.key).Select(n => n.niches.Select(a => new NicheFilter { UrlId = a.UrlId, UrlName = a.UrlName, Name = a.Name }).ToList()).SingleOrDefault() } }) .ToList()) .SingleOrDefault(), Hidden = categoryData.Where(x => !x.key).Select(x => x.categories .Select(z => new CategoryFilter { UrlId = z.UrlId, UrlName = z.UrlName, Name = z.Name }) .ToList()).SingleOrDefault() }; } else { filters.CategoriesFilter = new CategoriesFilter { Visible = categoryData.Select(x => x.categories .Select(z => new CategoryFilter { UrlId = z.UrlId, UrlName = z.UrlName, Name = z.Name, Niches = new NichesFilter { ShowHidden = false, Visible = z.Niches.Where(w => w.key).Select(n => n.niches.Select(a => new NicheFilter { UrlId = a.UrlId, UrlName = a.UrlName, Name = a.Name }).ToList()).SingleOrDefault(), Hidden = z.Niches.Where(w => !w.key).Select(n => n.niches.Select(a => new NicheFilter { UrlId = a.UrlId, UrlName = a.UrlName, Name = a.Name }).ToList()).SingleOrDefault() } }) .ToList()) .SingleOrDefault(), }; } // ******Price Filter******** List <PriceFilterOption> priceFilterOptions = new List <PriceFilterOption>(); var priceRanges = await context.PriceRanges.AsNoTracking().ToListAsync(); if (queryParams.PriceFilter != null) { // Clear the price filter var priceFilter = queryParams.PriceFilter; queryParams.PriceFilter = null; // Query products without the price filter var prods = await GetProducts(queryParams, x => new { x.MinPrice, x.MaxPrice }); // Get the selected price filter options var selectedPriceFilterOptions = priceFilter.Options .Select(x => x.Label.Split('-') .Select(z => int.Parse(z)) .ToArray()) .Select(z => new { min = z[0], max = z[1] }) .ToList(); // Get the price filter options based on the queried products priceFilterOptions = (from pr in priceRanges from p in prods orderby pr.Id where ((p.MinPrice >= pr.Min && p.MinPrice < pr.Max) || selectedPriceFilterOptions.Contains(new { min = pr.Min, max = pr.Max })) select new PriceFilterOption { Label = pr.Label, Min = pr.Min, Max = pr.Max }).ToList(); queryParams.PriceFilter = priceFilter; } else { priceFilterOptions = (from pr in priceRanges from p in products orderby pr.Id where (p.MinPrice >= pr.Min && p.MinPrice < pr.Max) select new PriceFilterOption { Label = pr.Label, Min = pr.Min, Max = pr.Max }).ToList(); } List <PriceFilterOption> options = priceFilterOptions.Distinct().ToList(); filters.PriceFilter = new PriceFilter { Caption = "Price", Options = options }; // ******Rating Filter******** IEnumerable <double> productRatings; List <QueryFilterOption> ratingOptions = new List <QueryFilterOption>(); // Check to see if we have a customer rating filter selected if (queryParams.RatingFilter != null) { // Remove the customer rating filter and query without it // This is so we can get other rating filters that belong in the results var ratingFilter = queryParams.RatingFilter; queryParams.RatingFilter = null; productRatings = await GetProducts(queryParams, x => x.Rating); queryParams.RatingFilter = ratingFilter; List <double> selectedRatingOptions = ratingFilter.Options.Select(x => Convert.ToDouble(x.Id)).ToList(); productRatings = productRatings.Concat(selectedRatingOptions).ToList(); } else { productRatings = products.Select(x => x.Rating).ToList(); } // Rating 4 and up if (productRatings.Count(x => x >= 4) > 0) { ratingOptions.Add(new QueryFilterOption { Id = 4 }); } // Rating 3 and up if (productRatings.Count(x => x >= 3 && x < 4) > 0) { ratingOptions.Add(new QueryFilterOption { Id = 3 }); } // Rating 2 and up if (productRatings.Count(x => x >= 2 && x < 3) > 0) { ratingOptions.Add(new QueryFilterOption { Id = 2 }); } // Rating 1 and up if (productRatings.Count(x => x >= 1 && x < 2) > 0) { ratingOptions.Add(new QueryFilterOption { Id = 1 }); } filters.RatingFilter = new QueryFilter { Caption = "Customer Rating", Options = ratingOptions }; // ******Custom Filters******** // Get all the filter option Ids that are related to the product Ids List <int> filterOptionIds = await context.ProductFilters .AsNoTracking() .Where(x => productIds .Contains(x.ProductId)) .Select(x => x.FilterOptionId) .Distinct() .ToListAsync(); var customFilters = queryParams.CustomFilters; foreach (var customFilter in customFilters) { queryParams.CustomFilters = customFilters.Where(x => x.Caption != customFilter.Caption).ToList(); await queryParams.SetFilteredProducts(context); var pIds = await GetProducts(queryParams, x => x.Id); List <int> optionsIds; List <int> filterOptIds = await context.FilterOptions .AsNoTracking() .Where(x => x.Filter.Name == customFilter.Caption) .Select(x => x.Id) .ToListAsync(); optionsIds = await context.ProductFilters .AsNoTracking() .Where(x => pIds .Contains(x.ProductId) && filterOptIds.Contains(x.FilterOptionId)) .Select(x => x.FilterOptionId).Distinct() .ToListAsync(); // Add the new option ids to the list filterOptionIds = filterOptionIds .Concat(optionsIds) .Concat(customFilter.Options.Select(x => x.Id).ToList()) .ToList(); } // Get the raw filter data consisting of filter name and filter option name var rawFilterData = await context.FilterOptions .AsNoTracking() .OrderBy(x => x.FilterId) .Where(x => filterOptionIds .Contains(x.Id)) .Select(x => new { filterName = x.Filter.Name, optionName = x.Name, optionId = x.Id }) .ToListAsync(); // Format the raw data into a list of filter data filters.CustomFilters = rawFilterData .GroupBy(x => x.filterName) .Select(x => new QueryFilter { Caption = x.Select(y => y.filterName).FirstOrDefault(), Options = x.Select(y => new QueryFilterOption { Id = y.optionId, Label = y.optionName }) .ToList() }) .ToList(); return(filters); }