I'd like to append multiple bool filters with NEST, but I can't (practically) do it in a single statement as I want to build a set of Bool filters depending on different conditions.
Something like this pseudo code:
// Append a filter
searchDescriptor.Filter(f => f.Bool(b => b.Must(m => m.Term(i => i.SomeProperty, "SomeValue"))));
if (UserId.HasValue)
{
// Optionally append another filter (AND condition with the first filter)
searchDescriptor.Filter(f => f.Bool(b => b.Must(m => m.Term(i => i.AnotherProperty, "MyOtherValue"))));
}
var result = Client.Search(searchDescriptor);
Now it seems when the second optional filter is appended, it essentially replaces the first filter.
I'm sure I'm missing something syntactically, but I can't figure it out and the NEST documentation is a bit thin on the filter DSL. :)
The section on writing queries pretty much applies to filters as well: https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/writing-queries.html
The solution you ended up with is less than ideal since you are wrapping bool
filters inside an and
filter which have very different caching mechanisms (and filters don't use the cached bitsets so in most cases perform worse then regular bool filters).
Highly recommend reading http://www.elastic.co/blog/all-about-elasticsearch-filter-bitsets/ as it explains really well what the differences between and/or/not filters vs bool filters are.
You can actually rewrite this like so:
Client.Search(s=>s
.Filter(f=> {
BaseFilter ff = f.Term(i => i.MyProperty, "SomeValue");
if (UserId.HasValue)
ff &= f.Term(i => i.AnotherProperty, "AnotherValue");
return ff;
})
);
If the second term is searching using UserId you can take advantage of NEST's conditionless queries
Client.Search(s=>s
.Filter(f=>
f.Term(i => i.MyProperty, "SomeValue")
&& f.Term(i => i.AnotherProperty, UserId)
)
);
If UserId
is null then the term query won't be generated as part of the query, nest in this case won't even wrap the single remaining term in a bool filter but just send it as a plain term filter instead.
Ah, something like this seems to work:
var filters = new List<BaseFilter>();
// Required filter
filters.Add(new FilterDescriptor<MyType>().Bool(b => b.Must(m => m.Term(i => i.MyProperty, "SomeValue"))));
if (UserId.HasValue)
{
filters.Add(new FilterDescriptor<MyType>().Bool(b => b.Must(m => m.Term(i => i.AnotherProperty, "AnotherValue"))));
}
// Filter with AND operator
searchDescriptor.Filter(f => f.And(filters.ToArray()));
var result = Client.Search(searchDescriptor);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With