Search code examples
elasticsearchelasticsearch-dsl

Filter nested sorting in elasticsearch


I have a document with a nested structure the nested object has an assignment_name and a due_date:

The mapping

{
  "goal": {
    "mappings": {
      "doc": {
        "properties": {
          "title": {
            "type": "keyword"
          },
          // lot's of other fields here ...
          "steps": {
            "type": "nested",
            "properties": {
              "assignment_name": {
                "type": "keyword"
              },
              "due_date": {
                "type": "date"
              }
              // lots of other fields here
            }
          }
        }
      }
    }
  }
}

I want to:

  1. Filter all document that have a specific assignment_name (e.g.user_a)
  2. Sort the result by the next due_date, not taking other assignements into account.

This query gives me random result (no sortings):

{  
   "query":{  
      "bool":{  
         "filter":[  
            {  
               "nested":{  
                  "path":"steps",
                  "query":{  
                     "term":{  
                        "steps.assignment_name":"user_a"
                     }
                  }
               }
            }
         ]
      }
   },
   "sort":[  
      {  
         "steps.due_date":{  
            "order":"asc",
            "nested":{  
               "path":"steps",
               "filter":{  
                  "term":{  
                     "steps.assignment_name":"user_a"
                  }
               }
            }
         }
      }
   ],
   "from":0,
   "size":25
}

Solution

  • Firstly you need to ensure that datatype for steps field is nested. Then you have to use nested sorting to sort documents based on a nested document field.

    The query would be:

    {
      "query": {
        "bool": {
          "filter": [
            {
              "nested": {
                "path": "steps",
                "query": {
                  "term": {
                    "steps.assignment_name": "user_a"
                  }
                }
              }
            }
          ]
        }
      },
      "sort": [
        {
          "steps.due_date": {
            "order": "asc",
            "nested": {
              "path": "steps",
              "filter": {
                "term": {
                  "steps.assignment_name": "user_a"
                }
              }
            }
          }
        }
      ]
    }
    

    The catch above is to use the same filter in sort as used in the main query to filter the documents. This ensures that the correct nested document's field value is considered to sort the documents.