Search code examples
elasticsearchnestdslelasticsearch-dslelasticsearch-query

Dinamically add filter clause in QueryContainer


I already have two QueryDescriptor variables holding a boolean query build dynamically, like:

QueryContainer should_container = new QueryContainer();
QueryContainer filter_container = new QueryContainer();

foreach (var parameter in should_parameters) {
    should_container |= constructClause(parameter);
}
foreach (var parameter in filter_parameters) {
    filter_container &= constructClause(parameter);
}

When I try to merge this two variables to construct my query, like this:

var result = client.Search<ElasticSearchProject>(s=>s
    .From(0)
    .Size(10)
    .Query(qr => qr
        .Bool(b => b
            .Should(should_container)
            .Filter(filter_container)
        )
    )
);

debugging the result variable it returns:

"query": {
    "bool": {
        "should" : [
            "bool": {
                "should": [
                    {...},
                    {...}
                ]
            }
        ],
        "filter": [
            "bool": {
                "must": [
                    {...},
                    {...}
                ]
            }
        ]

Which is not incorrect! But I wonder if there is a way to avoid using this two should clauses, and get the following output:

"query": {
    "bool": {
        "should" : [
            {...},
            {...}
        ],
        "filter": [
            "bool": {
                "must": [
                    {...},
                    {...}
                ]
            }
        ]

That gives me the exactly same result. How can I write it with NEST to get the above query? I'm using elasticsearch 6.8.0


Solution

  • All bool query should, must, filter, must_not clauses accept a params QueryContainer[] of queries, so for each clause, you could use a List<QueryContainer> to collect the queries for the clause, then .ToArray() the list

    var client = new ElasticClient();
    
    var should_container = new List<QueryContainer>();
    var filter_container = new List<QueryContainer>();
    
    // TODO: add queries to clause lists
    
    var result = client.Search<ElasticSearchProject>(s => s
        .From(0)
        .Size(10)
        .Query(qr => qr
            .Bool(b => b
                .Should(should_container.ToArray())
                .Filter(filter_container.ToArray())
            )
        )
    );
    

    If you have a lot of queries in clauses, this will be faster than combining many queries with the overloaded operators.