Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


These support forums are now closed for new topics and comments.
Please head on over to http://eureka.ucommerce.net/ for support.

  • Chris 34 posts 134 karma points
    Jun 01, 2015 @ 17:46
    Chris
    0

    Exclude varient prices from Facets

    On my product definition I have some properties that are set as "Use in Faceted search", and I'm using the example code on the uCommerce site to get products like this: 

    var products = SearchLibrary.GetProductsFor(category, facets);
    

    This works great and the correct number of products are being returned, however I've noticed an issue where the Prices displayed in my list of facets are not based on Products but on Product Variants. I have 2 products, the first with 2 variants, the second with 4 variants. When I use the code below the Facet for prices has a hit count of 6:

    SearchLibrary.GetFacetsFor(category, facets)
    

    Is there a way of customizing the query to not return hits that are variants? I've tried this but I get no results:

    var topLevelProductsOnly =
                        SearchLibrary.FacetedQuery().Where(x => x.Variants.Any()).ToList();
  • Søren Spelling Lund 1797 posts 2786 karma points
    Jun 02, 2015 @ 14:24
    Søren Spelling Lund
    0

    Hi Chris,

    The reason you're not getting any results from the query you mention is that the field is not included in the default facet index. I have changed the default index to include this field going forward.

    Meanwhile, you can fix this by changing the SaveLanguage pipeline (this is where the index is created and recreated when necessary) to include the Variants value.

    The task replaces the existing one by registering it in Custom.config using component id "Language.CreateIndex":

    <component id="Language.CreateIndex"
    service="UCommerce.Pipelines.IPipelineTask`1[[UCommerce.Infrastructure.Globalization.Language, UCommerce.Infrastructure]], UCommerce"
        type="MyNamespcae.CreateIndexTask, MyDll" />

    And the implementation to include the new field:

    public class CreateIndexTask : IPipelineTask<Infrastructure.Globalization.Language>
        {
            private readonly IRavenDbStoreProvider _storeProvider;
            private readonly IRepository<PriceGroup> _priceGroupRepository;
    
            public CreateIndexTask(IRavenDbStoreProvider storeProvider, IRepository<PriceGroup> priceGroupRepository)
            {
                _storeProvider = storeProvider;
                _priceGroupRepository = priceGroupRepository;
            }
    
            public PipelineExecutionResult Execute(Infrastructure.Globalization.Language subject)
            {
                var store = _storeProvider.GetStore();
    
                // Uses the display name of fields to create dynamic fields
                // and the display names of data type pre values to create field value.
                // If name or pre value doesn't have a language specific value it
                // uses the values as stored on product document.
                string indexDefinition = @"docs.Products.Select(product => new {
                                            product.ProductDefinition,
                                            product.ThumbnailImageUrl,
                                            product.PrimaryImageUrl,
                                            product.Sku,
                                            product.VariantSku,
                                            product.Name,
                                            product.DisplayOnSite,
                                            product.Weight,
                                            product.AllowOrdering,
                                            product.ModifiedBy,
                                            product.ModifiedOn,
                                            product.CreatedOn,
                                            product.CreatedBy,
                                        product.Variants,
                                            Rating = this.Recurse(product, x => x.Variants).Select(x => new[] {x.Rating}),
                                            product.CategoryIds,
                                            _ = this.Recurse(product, x => x.Variants).Select(x => x.Properties.Select(y => y.Value.Select(z => (z.Value is string ? (IEnumerable<object>) new [] { z.Value } : (IEnumerable<object>) z.Value).Select(v => this.CreateField(LoadDocument(product.ProductDefinition).Fields.SingleOrDefault(field => field.Name == z.Key).Properties[""{CULTURECODE}""][""DisplayName""] ?? z.Key, LoadDocument(LoadDocument(product.ProductDefinition).Fields.SingleOrDefault(field => field.Name == z.Key).DataTypeId).PreValues.SingleOrDefault(preValue => preValue.Value == v).Properties[""{CULTURECODE}""][""DisplayName""] ?? v))))),
                                            __ = this.Recurse(product, x => x.Variants).Select(x => x.Prices.Select(y => this.CreateField(y.Key, y.Value)))
                                        })".Replace("{CULTURECODE}", subject.CultureCode); // string.Format doesn't work with @literals
    
                string indexName = "Products/ByPropertyRecurse/{0}".FormatWith(subject.CultureCode);
                store.DatabaseCommands.DeleteIndex(indexName);
    
                var index = new IndexDefinition()
                {
                    Map = indexDefinition,
                    Analyzers =
                    {
                        {"__all_fields", "KeywordAnalyzer"}
                    }
                };
    
                foreach (var priceGroup in _priceGroupRepository.Select(x => !x.Deleted))
                {
                    index.SortOptions.Add(priceGroup.Name, SortOptions.Double);
                }
    
                store.DatabaseCommands.PutIndex(indexName, index);
    
                return PipelineExecutionResult.Success;
            }
        }
  • Chris 34 posts 134 karma points
    Jun 02, 2015 @ 16:07
    Chris
    0

    Hi Soren,

    Thanks for that code, I've added it and I now only get the expected 2 products and not the variants using this code:

    var topLevelProductsOnly =
                        SearchLibrary.FacetedQuery().Where(x => x.Variants.Any()).ToList();

     

    I'm trying to use the ToFacets() to only get Facets matching these 2 products, however the below code returns a list of Facets that include the Price Facet that has a Hit count of 6, not 2 which is including the Variant prices. Am I correct in thinking this should only return Facet values based on the LINQ query, or is there something extra I need to do here?

    var topLevelProductsOnlyWithFacets =
                       SearchLibrary.FacetedQuery().Where(x => x.Variants.Any()).ToFacets().ToList();

    Thanks

    Chris

  • Søren Spelling Lund 1797 posts 2786 karma points
    Jun 16, 2015 @ 09:37
    Søren Spelling Lund
    0

    Please refer to answer in this topic on how to filter the returned facets.

    https://our.umbraco.org/projects/website-utilities/ucommerce/ucommerce-support/65289-Price-facet-returns

  • Chris 34 posts 134 karma points
    Jun 17, 2015 @ 12:49
    Chris
    0

    Hi Soren,

    I think for this my issue is more to do with unexpected values being returned and not filtering.

    The Price facet returned in the below method call has 6 hits which looks as if it is including the variant prices.

    var topLevelProductsOnlyWithFacets =
                       SearchLibrary.FacetedQuery()
                        .Where(x => x.CategoryIds.Any(y => y == categoryInt) && x.Variants.Any()).ToFacets()
                        .ToList();
    

    There are 2 products and 6 variants of these products, which explains the 6 hits for the price facet. However as I'm including the x.Variants.Any() LINQ clause i was expecting these to be filtered out. Is there a way to exclude variant prices from the values returned?

    Thanks

Please Sign in or register to post replies

Write your reply to:

Draft