Filter by dynamic fields

Member since: 2003

Let say you are indexing Product object that have some common properties but also other properties that vary based on product type.
Typically something this:

Product A: name:"Cannondale Synapse", model:"synapse", brand: "Cannondale", carbonframe: "yes", gearsystem: "Shimano Ultergra"
Product B: name:"Cannondale CAAD10", model:"CAAD 10", brand: "Cannondale", carbonframe: "no", gearsystem: "Shimano 105"
Product C: name:"Jotun lady", model:"Lady", brand: "Jotun", type: "waterpaint", drytime: "1 hour"

Product A and B are bikes, while C is paint. These have common properties (name, model, brand) and then other properties that vary by type.

How can I search and filter based on these last "dynamic" properties?

My first idea was to store them in a Dictionary property on the Products object, but I can´t get to work. Ref Twitter-conversation

The Dictionary2Find project is compiled against EPiServer.Find for CMS 7 (I´m using CMS 6), and could not get it to compile with Find version 1.0.0.170.
 

#64034 Dec 07, 2012 20:18
  • Hi Mari,

    I think Henrik may be able to help you get Dictionary2Find to work with the .NET 3.5 version. However, you should upgrade to the latest of that version (1.0.0.278 at this time).

    Given that you're running build 278 you could also try to have a property of type Dictionary<string, IndexValue>. IndexValue is a special little class that can hold either a string, integer, double or datetime, which based on what you write probably would work for your needs.If you try that approach I'd love to hear how it goes.

    Also, IndexValue is implicitly convertible from the above mentioned types, meaning that if you have a property named A of type Dictionary<string, IndexValue> you can do:

    obj.A["a"] = 1;

    obj.A["b"] = DateTime.Now;

    #64036 Edited, Dec 07, 2012 22:32
  • Member since: 2003

    Tried using version 1.0.0.278 and the IndexValue class, but it fails when trying to retrieve results, see error details below.
    I`ve tried indexing using both 

    Facets = new Dictionary<string, IndexValue> { { "carbon", "no" }, { "gears", "Shimano 105" } }

        
    and

    Facets = new Dictionary<string, IndexValue> { { "carbon", new IndexValue("no") }, { "gears", new IndexValue("Shimano 105") } }

        

    Unable to find a constructor to use for type EPiServer.Find.IndexValue. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.

    #64053 Dec 10, 2012 8:41
  • Are you getting that when results are retrieved? If I recall correctly you should be able to filter by values in a dictionary with IndexValue as well as project from them. However I don't think the class was designed for actually retrieving. Not that it was explictly design not to be retrievable, but it was designed for extensibility in Unified Search.

    Are you retrieving the indexed objects directly without any projection? Would adding a projection work for you?

    #64054 Dec 10, 2012 8:47
  • Member since: 2003

    Did some more quick testing (see results below) - will investigate further

    // works for retrieving all items
                var res1 = client.Search<ProductIndexedEntry>().
                    Select(x => new ProductIndexedEntry
                    {
                        Name = x.Name,
                        Model = x.Model
                    }).GetResult();
    
                // not working - throws error specified in previous post
                var res2 = client.Search<ProductIndexedEntry>().GetResult();
    
                // try to filter based on Dictionary key, not working - no results
                var res3 = client.Search<ProductIndexedEntry>().Filter(
                    x => x.Facets.MatchContained(a => a.Key, "carbon")
                        ).GetResult();
    
                // not building: "Cannot convert lambda expression to type 'EPiServer.Find.Api.Querying.Filter' because it is not a delegate type
                var res4 = client.Search<ProductIndexedEntry>().Filter(
                    x => x.Facets.MatchContained(a => a.Value, new IndexValue("yes"))
                        ).GetResult();

        

    #64055 Dec 10, 2012 9:22
  • I'm a bit unsure how this works in the .NET 3.5 version but in the .NET 4/CMS 7 version you should be able to do this:

    Filter(x => x.Facets["carbon"].Match("yes"))

     

    #64056 Dec 10, 2012 9:33
  • Member since: 2003

    If I go back to Dictionary<string,string> querying by value works:

    Filter(x => x.Facets["carbon"].Match("yes")).

    I'm not able to query by key (retrieving all items that has Facets key = "someKey"), but I guess I don't need that.

    #64061 Edited, Dec 10, 2012 13:05
  • Great!

    Filter(x => x.Facets["carbon"].Exists()) should give you by key I think.

    #64070 Dec 10, 2012 14:39
  • Hi Mari,

    Dictionary2Find work with the latest version of Find for CMS 6R2 (1.0.0.278) and now also supports filtering on keys or values.

    /Henrik

    #64143 Dec 11, 2012 13:25