NEST Conditional filter query with multiple terms
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)) ))));
The Filter
method of a bool query takes a params Func<QueryContainerDescriptor<T>, QueryContainer>[]
so that you can pass it multiple expressions to represent multiple filters
var nameList = new string[] { "name1", "name2" };var colorList = new string[] { "orange", "red" };client.SearchAsync<MyDocument>(s => s .Index("myindex") .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)) ) ) ));
which results in
{ "query": { "bool": { "filter": [ { "terms": { "name": [ "name1", "name2" ] } }, { "terms": { "color": [ "orange", "red" ] } } ] } }}
NEST also has the concept of conditionless queries, that is, if a query is determined to be conditionless, then it will not be serialized as part of the request.
What does it mean to be conditionless? Well, that depends on the query; for example, in the case of a terms
query it is deemed to be conditionless if any of the following are true
- the
field
doesn't have a value - the term values list is
null
- the terms value is an empty collection
- the terms values list has values but they are all
null
or empty strings
To demonstrate
var emptyNames = new string[] {};string[] nullColors = null;client.SearchAsync<MyDocument>(s =>s.Index("myindex") .Query(q => q .Bool(bq => bq .Filter( fq => fq.Terms(t => t.Field(f => f.Name).Terms(emptyNames)), fq => fq.Terms(t => t.Field(f => f.Color).Terms(nullColors))) ) ));
results in
{}
Conditionless queries serve to make writing NEST queries easier in that you don't need to check if the collection has values before constructing a query. You can change conditionless semantics on a per query basis using .Strict()
and .Verbatim()
.
var searchResponse = client.Search<EventData>(s => s .From(0) .Query(q => q .Bool(bq => bq .Filter( fq => fq.Terms(t => t.Field(f => f.Client.Id).Terms(17)), fq => fq.Terms(t => t.Field(f => f.Item.Id).Terms(**new[] { 34983, 35430, 35339, 35300 }**)), fq => fq.Terms(t=>t.Field(f=>f.Event).Terms("Control de Panico")), fq => fq.DateRange(dr => dr.Field(f => f.DateTime) .GreaterThanOrEquals(new DateTime(2018, 07, 01)) .LessThanOrEquals(new DateTime(2018, 10, 02))) ) )) .Size(2000) .Sort(g => sortDescriptor) );