0

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?

1
  • Note that in if statement the date range query include the the end time (by using "LessThanOrEqual" in NEST query) and else statement excludes the end time by using only LessThan in NEST query. Commented May 14, 2016 at 12:38

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot for valuable solution

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.