"Dynamically" creating a filter in NEST

c#, elasticsearch, nest

Solution

Using the lambda based DSL you can do the following:

var termsFilters = from tp in termParameters
                   let field = ToCamelCaseNestedNames(tp.SearchField)
                   let terms = tp.SearchValues
                   select Filter.Terms(field, terms);

var prefixFilters = from tp in prefixParameters
                    let field = ToCamelCaseNestedNames(tp.SearchField)
                    let prefix = tp.SearchValues.FirstOrDefault().ToLowerInvariant()
                    select Filter.Prefix(field, prefix);

var search = client.Search(s => s
    .From(0)
    .Size(20)
    .Filter(f => f.And(termsFilters.Concat(prefixFilters).ToArray()))
);

Which i think reads a bit better :)

Nest now also supports `conditionless` queries so if any `tp.SearchValues` is `null`, `empty` or `all empty strings` or `tp.SearchField` is `null or empty` it will skip that terms/prefix query.

You can revert this behavior easily though:

var search = client.Search(s => s
    .Strict()
    .From(0)
    .Size(20)
    .Filter(f => f.And(termsFilters.Concat(prefixFilters).ToArray()))
);

which will throw a `DslException` if an empty query is generated.

As a last note `client.Search()` will return a `QueryResult<dynamic>` if you can strongly type your documents so can do a `client.Search<MyDocument>()`.

Problem

I have an interesting challenge, which I think there is an easy answer to. I know that NEST filters work correctly when syntactically you do something like this: ``` var andFilter = FilterFactory.AndFilter( FilterFactory.TermFilter("name.first", "shay1"), FilterFactory.TermFilter("name.first", "shay4") ); ``` My base services should allow an the caller to pass in some sort of enumerable list of items to filter. I'd basically like to be able programmatically achieve something like this (filters is passed into the method): ``` var andFilter = new FilterDescriptor(); foreach (var filter in filters) { andFilter = filter concatenated to andFilter } ``` In other words if I passed in an array of { {"first.name", "joe"}, {"first.name", "jim"}, {"first.name", "frank"}} I would like to produce the equivalent of ``` var andFilter = FilterFactory.AndFilter( FilterFactory.TermFilter("name.first", "joe"), FilterFactory.TermFilter("name.first", "joe"), FilterFactory.TermFilter("name.first", "frank") ); ```

Original source