简体   繁体   中英

how to write dynamic elastic search query in NEST C#

I have a function which does a search on documents in a time interval, based on a boolean flag, the NEST query would be different to use LessThanOrEqual in if statment and LessThan in else statement.

public IEnumerable<Book> GetBooks(DateTime startTime, DateTime endTime,  string author, bool includeEnd)
{
  var readRecords;
  if (includeEnd){
      readRecords = elastic.Search<Book>(s => s.Index(IndexName)
      .Query(q => q.Term(book => book.Author, author) &&
            q.DateRange(i => i.Field(book => book.Author)    
            .GreaterThanOrEquals(startTime)
            .LessThanOrEquals(endTime)))).Documents.ToArray();      
  }
  else{
    readRecords = elastic.Search<Book>(s => s.Index(IndexName)
           .Query(q => q.Term(book => book.Author, author) &&
            q.DateRange(i => i.Field(book => book.Author)
            .GreaterThanOrEquals(startTime)
            .LessThan(endTime)))).Documents.ToArray();
    }   
    return readRecords;
}

How can I make this NEST query dynamic using the boolean flag "includeEnd" so that I do not need to use the if statement?

Just take a look at what the LessThanOrEquals and LessThan generic extension methods do. Basically, they extend a DateRangeQueryDescriptor of T (in this case, T is a Book), accept a DateMath argument, and return another DateRangeQueryDescriptor. So, we can just break out a function that, depending on the includeEnd flag, returns the correct function to expect the query descriptor.

public IEnumerable<Book> GetBooks(DateTime startTime, DateTime endTime, string author, bool includeEnd)
{
    var dateFilter = includeEnd ?
        // you have to do a little casting for the lambdas to know what type we're returning
        (Func<DateRangeQueryDescriptor<Book>, DateRangeQueryDescriptor<Book>>)
        (q => q.LessThanOrEquals(endTime))
        : q => q.LessThan(endTime);

    return elastic.Search<Book>(s => s
        .Index(IndexName)
        .Query(q => q.Term(book => book.Author, author) &&
                    q.DateRange(i =>
                    {
                        i = i.Field(book => book.Author)
                        .GreaterThanOrEquals(startTime);
                        return dateFilter(i);
                    }
            )))
            .Documents
            .ToArray();
}

To take this idea further, you could write your own extension method:

public static class DateQueryExtensions
{
    public static DateRangeQueryDescriptor<T> LessThanWithOption<T>(this DateRangeQueryDescriptor<T> q, DateMath to, bool includeEnd)
        where T : class
    {
        return includeEnd ? q.LessThanOrEquals(to) : q.LessThan(to);
    }
}

Then you can use it like this:

public IEnumerable<Book> GetBooksUsingExtension(DateTime startTime, DateTime endTime, string author, bool includeEnd)
{
    return elastic.Search<Book>(s => s
       .Index(IndexName)
       .Query(q => q.Term(book => book.Author, author) &&
                   q.DateRange(i => i.Field(book => book.Author)
                       .GreaterThanOrEquals(startTime)
                       .LessThanWithOption(endTime, includeEnd)
                   )))
           .Documents
           .ToArray();

}

Most of the Nest fluent interface extensions operate on query descriptors in a similar manner.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM