Search code examples
elasticsearchnest

Nest ElasticSearch adding conditional Terms


I have the following Query that I am building up, notice that filtering on the companyGroupId I cant seem to find suitable way to add and conditional Term.

I would like to check the includeTerminationDate value and conditionally add the term

So in a nutshell, if false don't return records with an termination date.

private Func<QueryContainerDescriptor<EmployeeDocument>, QueryContainer> EmployeeSearchQuery(string query, long companyGroupId, bool includeTerminationDate)
        {
            return q => q
                            .MultiMatch(m => m
                                .Query(query)

                                .Type(TextQueryType.MostFields)
                                .MinimumShouldMatch("90%")
                                .Fields(f => f
                                    .Field(ff => ff.FullName, 3)
                                    .Field(ff => ff.Number, 3)
                                    .Field(ff => ff.Email)
                                    .Field(ff => ff.JobNumber)
                                    .Field(ff => ff.Description))) && q.Term(f => f.CompanyGroupId, companyGroupId);
        }

The one why would just be to duplicate the code and add the Term per the condition. But i would like to keep to the DRY Principle. The other way would be something like the below, which I cant seem to figure out.

return q => q
                            .MultiMatch(m => m
                                .Query(query)

                                .Type(TextQueryType.MostFields)
                                .MinimumShouldMatch("90%")
                                .Fields(f => f
                                    .Field(ff => ff.FullName, 3)
                                    .Field(ff => ff.Number, 3)
                                    .Field(ff => ff.Email)
                                    .Field(ff => ff.JobNumber)
                                    .Field(ff => ff.Description))) && q.Term(f => f.CompanyGroupId, companyGroupId)
                                                                     && !includeTerminationDate ? q.Term(f => f.TerminationDate, null) : 'Otherwise do not include term';

Solution

  • One way to achieve this would be to convert the expression to a method group, and conditionally add the query

    private Func<QueryContainerDescriptor<EmployeeDocument>, QueryContainer> EmployeeSearchQuery(string query, long companyGroupId, bool includeTerminationDate)
    {
        return q =>
        {
            var qc = q.MultiMatch(m => m
                       .Query(query)
                       .Type(TextQueryType.MostFields)
                       .MinimumShouldMatch("90%")
                       .Fields(f => f
                           .Field(ff => ff.FullName, 3)
                           .Field(ff => ff.Number, 3)
                           .Field(ff => ff.Email)
                           .Field(ff => ff.JobNumber)
                           .Field(ff => ff.Description))) && 
                    q.Term(f => f.CompanyGroupId, companyGroupId);
    
            // whatever your logic is for adding termination date
            if (includeTerminationDate)
                qc &= q.Term(f => f.TerminationDate, DateTime.UtcNow);
    
            return qc;
        };
    }
    

    Then to use

    client.Search<EmployeeDocument>(s => s
        .Query(EmployeeSearchQuery("query", 2, false))
    );
    

    emits

    {
      "query": {
        "bool": {
          "must": [
            {
              "multi_match": {
                "type": "most_fields",
                "query": "query",
                "minimum_should_match": "90%",
                "fields": [
                  "fullName^3",
                  "number^3",
                  "email",
                  "jobNumber",
                  "description"
                ]
              }
            },
            {
              "term": {
                "companyGroupId": {
                  "value": 2
                }
              }
            }
          ]
        }
      }
    }
    

    and

    client.Search<EmployeeDocument>(s => s
        .Query(EmployeeSearchQuery("query", 2, true))
    );
    

    emits

    {
      "query": {
        "bool": {
          "must": [
            {
              "multi_match": {
                "type": "most_fields",
                "query": "query",
                "minimum_should_match": "90%",
                "fields": [
                  "fullName^3",
                  "number^3",
                  "email",
                  "jobNumber",
                  "description"
                ]
              }
            },
            {
              "term": {
                "companyGroupId": {
                  "value": 2
                }
              }
            },
            {
              "term": {
                "terminationDate": {
                  "value": "2018-05-16T23:21:16.8309753Z"
                }
              }
            }
          ]
        }
      }
    }