Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 502
Hussein Salman Avatar asked Dec 11 '22 19:12

Hussein Salman


1 Answers

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)
    ))
like image 157
Drew Schneider Avatar answered Dec 31 '22 21:12

Drew Schneider