0
votes

I'm using elasticsearch nest within an asp.net mvc application.

Following elasticsearch query is throwing an exception because fields like categories and brands could be null or empty. How do add if statements and build the filters conditionally. Thank you!

I have to use bool & must to combine (AND) filters for search criteria. As an example a user want products in "shoes" category and retailer "macys".

 s.Query(q => q
                .Bool(bq => bq
                    .Must(
                        mq => mq.Filtered(fq => fq
                            .Filter(f => f.Terms("Categories", request.Categories))
                            ),
                        mq => mq.Filtered(fq => fq
                            .Filter(f => f.Terms("BrandName", request.Brands))
                            ),
                        mq => mq.Filtered(fq => fq
                            .Filter(f => f.Terms("RetailerName", request.Retailers))
                            ),
                        mq => mq.Filtered(fq => fq
                            .Filter(f => f.Terms("RetailerName", request.Retailers))
                            ),
                        mq => mq.Range(r => r
                            .OnField("SellingPrice")
                            .GreaterOrEquals((double)request.PriceRanges[0].Start)
                            .LowerOrEquals((double)request.PriceRanges[0].End)
                            )
                    )
                )
             );    
1

1 Answers

0
votes

You don't have to care about null or empty values passed to queries, because NEST has feature called Conditionless Queries. Documentation says

If any of the queries would result in an empty query they won't be sent to Elasticsearch.

The cause of the exception are these lines of code:

mq => mq.Range(r => r
    .OnField("SellingPrice")
    .GreaterOrEquals((double)request.PriceRanges[0].Start)
    .LowerOrEquals((double)request.PriceRanges[0].End)
)

Propably PriceRanges is null or empty, and you are trying to access Start and End properties from a first element. Would be great if you are able to change a request class to something like below, in case you are using only first item from PriceRanges:

class Request
{
    public List<string> Categories { get; set; }
    public List<string> Brands { get; set; }
    public double? PriceRangeStart { get; set; }
    public double? PriceRangeEnd { get; set; }
}

Then your NEST query will look like:

s.Query(q => q
    .Bool(bq => bq
        .Must(
            mq => mq.Filtered(fq => fq
                .Filter(f => f.Terms("Categories", request.Categories))
                ),
            mq => mq.Filtered(fq => fq
                .Filter(f => f.Terms("BrandName", request.Brands))
                ),
            mq => mq.Filtered(fq => fq
                .Filter(f => f.Terms("RetailerName", request.Retailers))
                ),
            mq => mq.Range(r => r
                .OnField("SellingPrice")
                .GreaterOrEquals(request.PriceRangeStart)
                .LowerOrEquals(request.PriceRangeEnd)
                )
        )
    ));

For this request object

var request = new Request
{
    Brands = new List<string>{"brand"},
    PriceRangesEnd = 100
};

NEST produces following elasticsearch query

"query": {
  "bool": {
    "must": [
      {
        "filtered": {
          "filter": {
            "terms": {
              "BrandName": [
                "brand"
              ]
            }
          }
        }
      },
      {
        "range": {
          "SellingPrice": {
            "lte": "100"
          }
        }
      }
    ]
  }
}