dynamicelasticsearchnestednestbooleanquery

Nest Elastic - Building Dynamic Nested Query


I have to query a nested object using Nest, however the query is built in dynamic way. Below is code that demonstrate using query on nested "books" in a static way

QueryContainer qry;
qry = new QueryStringQuery()
{
    DefaultField = "name",
    DefaultOperator = Operator.And,
    Query = "salman"
};

QueryContainer qry1 = null;

qry1 = new RangeQuery() // used to search for range ( from , to)
{
    Field = "modified",
    GreaterThanOrEqualTo = Convert.ToDateTime("21/12/2015").ToString("dd/MM/yyyy"),
};

QueryContainer all = qry && qry1;

var results = elastic.Search<Document>(s => s
   .Query(q => q
        .Bool(qb => qb
            .Must(all)))
    .Filter(f =>
            f.Nested(n => n
                 .Path("books")
                    .Filter(f3 => f3.And(
                                f1 => f1.Term("book.isbn", "122"),
                                f2 => f2.Term("book.author", "X"))

                            )
                    )
            )

    );

The problem is that i need to combine multiple queries (using And,OR operators) for "books" in dynamic fashion. For example, get the books that satisfy these set of conditions:

  1. Condition 1: Books that has Author "X" and isbn "1"
  2. Condition 2: Books that has Author "X" and isbn "2"
  3. Condition 3: Books that has Author "Z" and isbn "3"
  4. Other Condtions: .....

Now, the filter in the nested Query should retrieve books if:
Condition 1 AND Condition 2 Or Condition 3

Suppose that i have class name FilterOptions that contains the following attributes:

  1. FieldName
  2. Value
  3. Operator (which will combine the next filter)

I am going to loop on the given FilterOptions array to build the query.

Question:

What should i use to build the nested query? Is it a FilterDesciptor and how to combine them add the nested query to the Search Method?

Please, recommend any valuable link or example?


Solution

  • I agree with paweloque, it seems your first two conditions are contradictory and wouldn't work if AND-ed together. Ignoring that, here's my solution. I've implemented this in such a way that allows for more than the three specific conditions you have. I too feel it would fit better in a bool statement.

    QueryContainer andQuery = null;
    QueryContainer orQuery = null;
    foreach(var authorFilter in FilterOptions.Where(f=>f.Operator==Operator.And))
    {
        andQuery &= new TermQuery
        {
            Field = authorFilter.FieldName,
            Value = authorFilter.Value
        };
    }
    foreach(var authorFilter in FilterOptions.Where(f=>f.Operator==Operator.Or))
    {
        orQuery |= new TermQuery
        {
            Field = authorFilter.FieldName,
            Value = authorFilter.Value
        };
    }
    

    After that, in the .Nested call I would put:

    .Path("books")
        .Query(q=>q
            .Bool(bq=>bq
                .Must(m=>m.MatchAll() && andQuery)
                .Should(orQuery)
        ))