Composite aggregations and pagination

Here's an example on how to do forward and reverse pagination with a composite aggregation.

Example data, for use in Kibana's Dev Tools:

POST test/_doc
{
  "date": "2020-01-01",
  "product": "a"
}
POST test/_doc
{
  "date": "2020-01-02",
  "product": "b"
}
POST test/_doc
{
  "date": "2020-01-03",
  "product": "c"
}
POST test/_doc
{
  "date": "2020-01-04",
  "product": "d"
}
POST test/_doc
{
  "date": "2020-01-05",
  "product": "e"
}

Run our first query:

GET /_search
{
  "size": 0,
  "aggs": {
    "my_buckets": {
      "composite": {
        "size": 2,
        "sources": [
          {
            "date": {
              "date_histogram": {
                "field": "date",
                "calendar_interval": "1d",
                "order": "desc"
              }
            }
          },
          {
            "product": {
              "terms": {
                "field": "product.keyword",
                "order": "asc"
              }
            }
          }
        ]
      }
    }
  }
}

Which returns:

  "aggregations" : {
    "my_buckets" : {
      "after_key" : {
        "date" : 1578096000000,
        "product" : "d"
      },
      "buckets" : [
        {
          "key" : {
            "date" : 1578182400000,
            "product" : "e"
          },
          "doc_count" : 1
        },
        {
          "key" : {
            "date" : 1578096000000,
            "product" : "d"
          },
          "doc_count" : 1
        }
      ]
    }
  }

Based on this you fetch the next page of the aggregation with the after_key:

GET /_search
{
  "size": 0,
  "aggs": {
    "my_buckets": {
      "composite": {
        "size": 2,
        "sources": [
          {
            "date": {
              "date_histogram": {
                "field": "date",
                "calendar_interval": "1d",
                "order": "desc"
              }
            }
          },
          {
            "product": {
              "terms": {
                "field": "product.keyword",
                "order": "asc"
              }
            }
          }
        ],
        "after": {
          "date": 1578096000000,
          "product": "d"
        }
      }
    }
  }
}

That gets you back:

  "aggregations" : {
    "my_buckets" : {
      "after_key" : {
        "date" : 1577923200000,
        "product" : "b"
      },
      "buckets" : [
        {
          "key" : {
            "date" : 1578009600000,
            "product" : "c"
          },
          "doc_count" : 1
        },
        {
          "key" : {
            "date" : 1577923200000,
            "product" : "b"
          },
          "doc_count" : 1
        }
      ]
    }
  }

Now if you want to go to the page before, instead of after, take the first bucket of this result:

      "key" : {
        "date" : 1578009600000,
        "product" : "c"
      }

And invert the asc and desc, so you get the following query for the before page:

GET /_search
{
  "size": 0,
  "aggs": {
    "my_buckets": {
      "composite": {
        "size": 2,
        "sources": [
          {
            "date": {
              "date_histogram": {
                "field": "date",
                "calendar_interval": "1d",
                "order": "asc"
              }
            }
          },
          {
            "product": {
              "terms": {
                "field": "product.keyword",
                "order": "desc"
              }
            }
          }
        ],
        "after": {
          "date": 1578009600000,
          "product": "c"
        }
      }
    }
  }
}

And that takes you to the previous page again:

"aggregations" : {
    "my_buckets" : {
      "after_key" : {
        "date" : 1578182400000,
        "product" : "e"
      },
      "buckets" : [
        {
          "key" : {
            "date" : 1578096000000,
            "product" : "d"
          },
          "doc_count" : 1
        },
        {
          "key" : {
            "date" : 1578182400000,
            "product" : "e"
          },
          "doc_count" : 1
        }
      ]
    }
  }

Source: Elastic Search Pagination.