0

I've got list of objects called selected which is this shape: List<{bool Selected, String Discriminator, List<int> Tags}>.

I need to say if document.VgnItm.Discriminator is one of selected[index].Discriminator, AND document.VgnItm.Tags has at least one tag from selected[index].Tags, then select that document.

This works when selected contains only one item:

for (var i = 0; i < selected.Count; i++)
{
    QueryContainer &= Query<VgnItmEstSearchDto>.Bool(boolean => boolean.Must(booleanMust =>
            booleanMust.Term(term => term.Field(termField => termField.VgnItm.Discriminator)
                .Value(selected[i].Discriminator)),
               booleanMust => booleanMust.Terms(terms => terms
                .Field(p => p.VgnItm.Tags)
                .Terms(selected[i].Tags)
            ))
    );
}

But when selected contains two or more items the QueryContainer &= means that the document.VgnItm.Discriminator must be selected[index1].Discriminator, and also selected[index2].Discriminator which is impossible. So it doesn't find any results.

What can I do here to make this work when selected contains multiple items? I can't just use QueryContainer |= because the QueryContainer has other clauses above. I tried wrapping Query<VgnItmEstSearchDto>.Bool(boolean => boolean.Must in a Bool.Should so it is a double Bool, but it had the same result.

BeniaminoBaggins
  • 11,202
  • 41
  • 152
  • 287

1 Answers1

0

I was able to do it by composing QueryContainers in the correct manner. As long as we compose like so: var compositeQueryContainer = childQueryA.QueryContainer &= childQueryB.QueryContainer, then having QueryContainer |= Query<VgnItmEstSearchDto>.Bool as I mentioned in my question, will not negate a previous query, it will combine them (AND them rather than OR them).

So I can create the custom query exactly how it is in the question but use an |= (OR) inside my loop, which builds a larger query container from every loop cycle:

public class ChildQueryB :
    BaseQuery<VgnItmEstSearchDto>
{
    public ChildQueryB(
        string searchTerm,
        List<DiscriminatorTags> selectedDiscriminatorTags = null,
        bool shouldSearchNumberFields = false) :
        base(searchTerm, shouldSearchNumberFields)
    {

        for (var i = 0; i < selectedDiscriminatorTags.Count; i++)
        {
            QueryContainer |= Query<VgnItmEstSearchDto>.Bool(boolean => boolean.Must(booleanMust =>
                    booleanMust.Term(term => term.Field(termField => termField.VgnItm.Discriminator)
                        .Value(selectedDiscriminatorTags[i].Discriminator)),
                       booleanMust => booleanMust.Terms(terms => terms
                        .Field(p => p.VgnItm.Tags)
                        .Terms(selectedDiscriminatorTags[i].Tags)
                    ))
            );
        }
    }
}

Then compose it with another child query in a parent query using &=:

public class CompositeQuery :
    BaseQuery<VgnItmEstSearchDto>
{
    public CompositeQuery(
        string searchTerm,
        List<DiscriminatorTags> selectedDiscriminatorTags = null,
        bool shouldSearchNumberFields = false) :
        base(searchTerm, shouldSearchNumberFields)
    {

        
        var childQueryA = new ChildQueryB(searchTerm, true);
        var childQueryB = new ChildQueryA(searchTerm, selectedDiscriminatorTags, true);
        base.QueryContainer = childQueryA.QueryContainer &=
            childQuery.QueryContainer;
    }
}

It can then be used like:

var compositeQuery = new CompositeQuery(searchTerm, discriminatorTags.Where(d => d.Selected == true).ToList(), true);
var results = searchService.Search(compositeQuery, pageNumber, pageSize);
BeniaminoBaggins
  • 11,202
  • 41
  • 152
  • 287