Search code examples
c#elasticsearchasp.net-core-webapinest

C# NEST nested filter to get values within the dateRange or NULL


I am developing something to show a pie chart of the users' age with slicing them as

  • 0-17
  • 18-34
  • 35-44
  • 44-54
  • 55+
  • Not Available

here i am getting the ages based on the date range;

var aggaResonse = client.Search<JSModel>(a => a
                  .Size(0)
                  .Query(q => q.Bool(b => b.Must(m => m
                                                            .DateRange(date => date
                                                            .Field(p => p.CreatedDate)
                                                            .GreaterThanOrEquals(start)
                                                            .LessThanOrEquals(end)),

                                                        m =>
                                                            m.Term(t => t.Field(f => f.StepType.Suffix("keyword")).Value("User"))

                                                      )
                  ))


                  .Aggregations(c => c.DateRange(nameof(AgeModel), x => x
                                                       .Field(f => f.BirthDate)
                                                       .Ranges(r => r.From(DateMath.Now.Subtract("17y")).To(DateMath.Now).Key(nameof(result.Years_0_17)),
                                                               r => r.From(DateMath.Now.Subtract("34y")).To(DateMath.Now.Subtract("18y")).Key(nameof(result.Years_18_34)),
                                                               r => r.From(DateMath.Now.Subtract("44y")).To(DateMath.Now.Subtract("35y")).Key(nameof(result.Years_35_44)),
                                                               r => r.From(DateMath.Now.Subtract("54y")).To(DateMath.Now.Subtract("45y")).Key(nameof(result.Years_45_54)),
                                                               r => r.From(DateMath.Now.Subtract("120y")).To(DateMath.Now.Subtract("55y")).Key(nameof(result.Years_55_Plus))

                                                               )


                                                 )
                        ));

            if (!aggaResonse.IsValid)
                return result;


            result.Years_0_17 = aggaResonse.Aggregations.Range(nameof(AgeModel)).Buckets.Single(c => c.Key == nameof(result.Years_0_17)).DocCount;
            result.Years_18_34 = aggaResonse.Aggregations.Range(nameof(AgeModel)).Buckets.Single(c => c.Key == nameof(result.Years_18_34)).DocCount;
            result.Years_35_44 = aggaResonse.Aggregations.Range(nameof(AgeModel)).Buckets.Single(c => c.Key == nameof(result.Years_35_44)).DocCount;
            result.Years_45_54 = aggaResonse.Aggregations.Range(nameof(AgeModel)).Buckets.Single(c => c.Key == nameof(result.Years_45_54)).DocCount;
            result.Years_55_Plus = aggaResonse.Aggregations.Range(nameof(AgeModel)).Buckets.Single(c => c.Key == nameof(result.Years_55_Plus)).DocCount;


            return result;

what i need is to have a "Not Available" slice for users who has NULL as birthdate with mapping it as;

result.Not_Available = ....;

Any suggestions with following best practices for nested NEST aggs ?

I was thinking to run another search which i guess it's not the best practice.


Solution

  • After digging documentations too much, here is the solution i wrote;

    I added a "Missing" attribute to the current aggregation;

    && c.Missing("DOBMissing", x => x.Field(f => f.BirthDate))
    

    So it became like;

    .Aggregations(c => c.DateRange(nameof(AgeModel), x => x
                                                           .Field(f => f.BirthDate)
                                                           .Ranges(r => r.From(DateMath.Now.Subtract("17y")).To(DateMath.Now).Key(nameof(result.Years_0_17)),
                                                                   r => r.From(DateMath.Now.Subtract("34y")).To(DateMath.Now.Subtract("18y")).Key(nameof(result.Years_18_34)),
                                                                   r => r.From(DateMath.Now.Subtract("44y")).To(DateMath.Now.Subtract("35y")).Key(nameof(result.Years_35_44)),
                                                                   r => r.From(DateMath.Now.Subtract("54y")).To(DateMath.Now.Subtract("45y")).Key(nameof(result.Years_45_54)),
                                                                   r => r.From(DateMath.Now.Subtract("120y")).To(DateMath.Now.Subtract("55y")).Key(nameof(result.Years_55_Plus))
                                                                   )
                                                     ) &&
                                    c.Missing("DOBMissing", x => x.Field(f => f.BirthDate))
                )
    

    And i'd accessed the "missing" part of aggregation as following;

    result.Not_Available = aggaResponse.Aggregations.Missing("DOBMissing").DocCount;