Filtering categories using AND filters inside an OR filter

Vote:
 

There was a previous post almost with same requirements there was no accepted answer in that post and my requirements are but different 

I am currently creating a service using Episerver Find. I have managed to get everything working apart from the filtering of Categories. From the API that is received in the solution, we get multiple lists of Categories that have been selected inside a category list.

E.g. 

var requiredCategories = new List<string>{"Category 1","Category 2"};

var optionalCategories = new List<string>{"Category 3","Category 4"};


After this, when searching using Find, I need to check for Content that has "Category 1 AND Category 2 AND Category 3" OR "Category 1 AND Category 2 AND Category 4". If none of the items have these categories assigned to them, or as an example only have Category 1 AND Category 3 assigned and not Category 2 assigned, no results should be returned.

Updated

if optionalCategories is empty then the logic is straight forward but if there are values in it, it makes the AND OR combination with requiredCategories

for example 

var requiredCategories = new List<string>{"Category 1","Category 2"};
var optionalCategories = new List<string>{"Category 3","Category 4"};

Find Query Should like this: Get me Articles which have [Categogy 1 AND Category 2 AND Category 3] OR [Categogy 1 AND Category 2 AND Category 4]

Now if
Article 1 has [Category 1, Category 2, Category 3]
Article 2 has [Category 1, Category 2, Category 4]
Article 3 has [Category 1, Category 3, Category 4]
Article 4 has [Category 2, Category 3]

Article 5 has [Category 1, Category 2]

According to the logic, only Article 1 & Article 2 qualifies and Article 3 , Article 4 & Article 5 should be rejected

I can not seem to find a way to do this. I Have tried a Filter Builder using the OR method and then passing that into the Search.Filter() method but that seems to get changed to an OR filter instead of an AND filter. Here is the code of that just in case I there is a mistake

//Code in a function

foreach (var category in optionalCategories)
{
var categoriesToMatch = new List<string> { category };
categoriesToMatch.AddRange(requiredCategories);

query = query.MatchCategories(categoriesToMatch);
}

// End of function

public static ITypeSearch MatchCategories(this ITypeSearch search, List<string> categoryList)
{
var categoryFilter = SearchClient.Instance.BuildFilter();

foreach (var category in categoryList)
{
categoryFilter = categoryFilter.And(x => x.PageCategories.Match(category);
}

return search.OrFilter(categoryFilter);
}

#207907
Edited, Oct 08, 2019 18:26
Vote:
 

Hi Rich, 

So if I understand correctly, you basically want to match on all required categories, and then any of the optional categories from the option list. 

If you change up your extension method slightly, pass two lists, create two filter builders for clarity, and combine the two at the bottom, using an And expression, I think it should give you what you need. 

I've written something up (not tested it unfortunately so can't vouch for its accuracy! :)). 

Hopefully it works and helps you out.

Paul 

public static ITypeSearch<T> MatchCategories<T>(this ITypeSearch<T> search, List<string> requiredCategoryList, List<string> optionalCategoryList) where T : IContent
        {
            var requiredFilter = new FilterBuilder<T>(search.Client);

            foreach (var category in requiredCategoryList)
            {
                requiredFilter = requiredFilter.And(x => x.PageCategories.Match(category));
            }

            var optionalFilter = new FilterBuilder<T>(search.Client);

            foreach (var category in optionalCategoryList)
            {
                optionalFilter = optionalFilter.Or(x => x.PageCategories.Match(category));
            }

            requiredFilter = requiredFilter.And(x => optionalFilter);

            return search.Filter(requiredFilter);
        }
#207926
Oct 08, 2019 17:44
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.