<p dir="auto">At the moment SingleBucketAggregator extends BucketAggregator and MultiBucketAggregation is a separate interface. This means that single bucket Aggregations are different from multi bucket aggregations which can lead to problems when traversing the aggregation response. The reason for this is that single bucket aggregations don't render the same way as multi-bucket ones and so while parsing a response you need to work out what type of aggregation you are looking at before you know how to parse it.</p>
<p dir="auto">If would be better if SingleBucketAggregator was a multi-bucket aggregator which just happened to only have a single bucket. In the response there would still be a 'buckets' field but it would only contain a single entry for single-bucket aggregations. This would mean that single and multi bucket aggregation could be treated the same both by users of the REST API and users of the JAVA API.</p>
<p dir="auto"><code class="notranslate">SingleBucketAggregations</code> (like filter aggregation) have no method <code class="notranslate">getBuckets()</code> and also the json response contains no buckets array. This saves some space but also makes it harder to traverse the aggregation tree because when looking at the result one always has to know if the aggregation that produced the current level was a <code class="notranslate">SingleBucketAggregation</code> or a <code class="notranslate">MultiBucketAggregation</code> (like terms agg).</p>
<p dir="auto">Example for json:</p>
<p dir="auto">Request with top level multi bucket agg:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="POST testidx/_search?size=0
{
  &quot;aggs&quot;: {
    &quot;terms&quot;: {
      &quot;terms&quot;: {
        &quot;field&quot;: &quot;label&quot;,
        &quot;size&quot;: 10
      },
      &quot;aggs&quot;: {
        &quot;histogram&quot;: {
          &quot;histogram&quot;: {
            &quot;field&quot;: &quot;num&quot;,
            &quot;interval&quot;: 1
          }
        }
      }
    }
  }
}"><pre class="notranslate"><code class="notranslate">POST testidx/_search?size=0
{
  "aggs": {
    "terms": {
      "terms": {
        "field": "label",
        "size": 10
      },
      "aggs": {
        "histogram": {
          "histogram": {
            "field": "num",
            "interval": 1
          }
        }
      }
    }
  }
}
</code></pre></div>
<p dir="auto">Request with top level single bucket agg:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="POST testidx/_search?size=0
{
  &quot;aggs&quot;: {
    &quot;terms&quot;: {
      &quot;filter&quot;: {
        &quot;term&quot;: {
          &quot;label&quot;: &quot;label_a&quot;
        }
      },
      &quot;aggs&quot;: {
        &quot;histogram&quot;: {
          &quot;histogram&quot;: {
            &quot;field&quot;: &quot;num&quot;,
            &quot;interval&quot;: 1
          }
        }
      }
    }
  }
}
"><pre class="notranslate"><code class="notranslate">POST testidx/_search?size=0
{
  "aggs": {
    "terms": {
      "filter": {
        "term": {
          "label": "label_a"
        }
      },
      "aggs": {
        "histogram": {
          "histogram": {
            "field": "num",
            "interval": 1
          }
        }
      }
    }
  }
}

</code></pre></div>
<p dir="auto">multi bucket yields:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&quot;aggregations&quot;: {
      &quot;terms&quot;: {
         &quot;doc_count_error_upper_bound&quot;: 0,
         &quot;sum_other_doc_count&quot;: 0,
         &quot;buckets&quot;: [
            {
               &quot;key&quot;: &quot;label_a&quot;,
               &quot;doc_count&quot;: 3,
               &quot;histogram&quot;: {
                  &quot;buckets&quot;: [
                     {
                        &quot;key&quot;: 1,
                        &quot;doc_count&quot;: 1
                     },
                    ...
"><pre class="notranslate"><code class="notranslate">"aggregations": {
      "terms": {
         "doc_count_error_upper_bound": 0,
         "sum_other_doc_count": 0,
         "buckets": [
            {
               "key": "label_a",
               "doc_count": 3,
               "histogram": {
                  "buckets": [
                     {
                        "key": 1,
                        "doc_count": 1
                     },
                    ...

</code></pre></div>
<p dir="auto">single bucket yields:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="
&quot;aggregations&quot;: {
      &quot;terms&quot;: {
         &quot;doc_count&quot;: 3,
         &quot;histogram&quot;: {
            &quot;buckets&quot;: [
               {
                  &quot;key&quot;: 1,
                  &quot;doc_count&quot;: 1
               },
               ...
"><pre class="notranslate"><code class="notranslate">
"aggregations": {
      "terms": {
         "doc_count": 3,
         "histogram": {
            "buckets": [
               {
                  "key": 1,
                  "doc_count": 1
               },
               ...

</code></pre></div>
<p dir="auto">although the two requests have the same level of "nestedness". If I was to post process the result I would have to change whichever application is consuming it when I change the top level aggregation from single to multibucket or the other way round.</p>
<p dir="auto">The following would be more convenient for the second request:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&quot;aggregations&quot;: {
    &quot;terms&quot;: {
      &quot;doc_count&quot;: 3,
      &quot;buckets&quot;: [
        {
          &quot;key&quot;: &quot;some_key_that_makes_sense&quot;,
          &quot;histogram&quot;: {
            &quot;buckets&quot;: [
              {
                &quot;key&quot;: 1,
                &quot;doc_count&quot;: 1
              },
            ...
"><pre class="notranslate"><code class="notranslate">"aggregations": {
    "terms": {
      "doc_count": 3,
      "buckets": [
        {
          "key": "some_key_that_makes_sense",
          "histogram": {
            "buckets": [
              {
                "key": 1,
                "doc_count": 1
              },
            ...

</code></pre></div>
<p dir="auto">This also affects the coming soon <code class="notranslate">getProperty</code> method for aggregations which is currently implemented to be consistent with the different behavior of single and multi buckets: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="48253172" data-permission-text="Title is private" data-url="https://github.com/elastic/elasticsearch/issues/8421" data-hovercard-type="pull_request" data-hovercard-url="/elastic/elasticsearch/pull/8421/hovercard?comment_id=20424480&amp;comment_type=review_comment" href="https://github.com/elastic/elasticsearch/pull/8421#discussion_r20424480">#8421 (comment)</a></p>