NEST Conditional filter query with multiple terms

dhrm picture dhrm · Jun 8, 2016 · Viewed 16.6k times · Source

I would like to do a ElasticSearch query like this:

{
    "query" :
    {
        "bool" :
        {
            "filter" : [
                {
                    "terms" :
                    {
                        "name" : ["name1", "name2"]
                    }
                },
                {
                    "terms" :
                    {
                        "color" : ["orange", "red"]
                    }
                }
            ]
        }
    }
}

I've tried to implement it in NEST like this:

_elasticClient
    .SearchAsync<MyDocument>(s =>
        s.Index("myindex")
            .Query(q => q
                .Bool(bq => bq
                    .Filter(fq =>
                    {
                        QueryContainer query = null;

                        if (nameList.Any()) {
                            query &= fq.Terms(t => t.Field(f => f.Name).Terms(nameList));
                        }

                        if (colorList.Any()) {
                            query &= fq.Terms(t => t.Field(f => f.Color).Terms(colorList));
                        }

                        return query;
                    })
                )
            )
    );

But that gives me a query like this where the filters are wrapped inside a bool must:

{
    "query" :
    {
        "bool" :
        {
            "filter" : [
                {
                    "bool" :
                    {
                        "must" : [
                            {
                                "terms" :
                                {
                                    "name" : ["name1", "name2"]
                                }
                            },
                            {
                                "terms" :
                                {
                                    "color" : ["orange", "red"]
                                }
                            }
                        ]
                    }
                }
            ]
        }
    }
}

How should I change my NEST code to give me the right query? Do have have to add my terms to something other then a QueryContainer?

Answer

Adam Łepkowski picture Adam Łepkowski · Jun 8, 2016

You can create a list of filters before you make a query if you want to check conditional filters as shown below:

var nameList = new[] {"a", "b"};
var colorList = new[] {1, 2};

var filters = new List<Func<QueryContainerDescriptor<MyDocument>, QueryContainer>>();
if (nameList.Any())
{
     filters.Add(fq=> fq.Terms(t => t.Field(f => f.Name).Terms(nameList)));
}

if (colorList.Any())
{
    filters.Add(fq => fq.Terms(t => t.Field(f => f.Color).Terms(colorList)));
}

ISearchResponse<Property> searchResponse =
     elasticClient.Search<MyDocument>(x => x.Query(q => q
     .Bool(bq => bq.Filter(filters))));

If you don't need to check any condition before making filter query then you can have something like that:

ISearchResponse<MyDocument> searchResponse =
elasticClient.Search<MyDocument>(x => x.Query(q => q
.Bool(bq => bq
.Filter(
        fq => fq.Terms(t => t.Field(f => f.Name).Terms(nameList)),
        fq => fq.Terms(t => t.Field(f => f.Color).Terms(colorList))
        ))));