Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Aggregations ›Bucket aggregations

Nested aggregation

A special single bucket aggregation that enables aggregating nested documents.

For example, lets say we have an index of products, and each product holds the list of resellers - each having its own price for the product. The mapping could look like:

resp = client.indices.create(
    index="products",
    mappings={
        "properties": {
            "resellers": {
                "type": "nested",
                "properties": {
                    "reseller": {
                        "type": "keyword"
                    },
                    "price": {
                        "type": "double"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.indices.create(
  index: 'products',
  body: {
    mappings: {
      properties: {
        resellers: {
          type: 'nested',
          properties: {
            reseller: {
              type: 'keyword'
            },
            price: {
              type: 'double'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.indices.create({
  index: "products",
  mappings: {
    properties: {
      resellers: {
        type: "nested",
        properties: {
          reseller: {
            type: "keyword",
          },
          price: {
            type: "double",
          },
        },
      },
    },
  },
});
console.log(response);
PUT /products
{
  "mappings": {
    "properties": {
      "resellers": { 
        "type": "nested",
        "properties": {
          "reseller": {
            "type": "keyword"
          },
          "price": {
            "type": "double"
          }
        }
      }
    }
  }
}

resellers is an array that holds nested documents.

The following request adds a product with two resellers:

resp = client.index(
    index="products",
    id="0",
    refresh=True,
    document={
        "name": "LED TV",
        "resellers": [
            {
                "reseller": "companyA",
                "price": 350
            },
            {
                "reseller": "companyB",
                "price": 500
            }
        ]
    },
)
print(resp)
response = client.index(
  index: 'products',
  id: 0,
  refresh: true,
  body: {
    name: 'LED TV',
    resellers: [
      {
        reseller: 'companyA',
        price: 350
      },
      {
        reseller: 'companyB',
        price: 500
      }
    ]
  }
)
puts response
const response = await client.index({
  index: "products",
  id: 0,
  refresh: "true",
  document: {
    name: "LED TV",
    resellers: [
      {
        reseller: "companyA",
        price: 350,
      },
      {
        reseller: "companyB",
        price: 500,
      },
    ],
  },
});
console.log(response);
PUT /products/_doc/0?refresh
{
  "name": "LED TV", 
  "resellers": [
    {
      "reseller": "companyA",
      "price": 350
    },
    {
      "reseller": "companyB",
      "price": 500
    }
  ]
}

We are using a dynamic mapping for the name attribute.

The following request returns the minimum price a product can be purchased for:

resp = client.search(
    index="products",
    size="0",
    query={
        "match": {
            "name": "led tv"
        }
    },
    aggs={
        "resellers": {
            "nested": {
                "path": "resellers"
            },
            "aggs": {
                "min_price": {
                    "min": {
                        "field": "resellers.price"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'products',
  size: 0,
  body: {
    query: {
      match: {
        name: 'led tv'
      }
    },
    aggregations: {
      resellers: {
        nested: {
          path: 'resellers'
        },
        aggregations: {
          min_price: {
            min: {
              field: 'resellers.price'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "products",
  size: 0,
  query: {
    match: {
      name: "led tv",
    },
  },
  aggs: {
    resellers: {
      nested: {
        path: "resellers",
      },
      aggs: {
        min_price: {
          min: {
            field: "resellers.price",
          },
        },
      },
    },
  },
});
console.log(response);
GET /products/_search?size=0
{
  "query": {
    "match": {
      "name": "led tv"
    }
  },
  "aggs": {
    "resellers": {
      "nested": {
        "path": "resellers"
      },
      "aggs": {
        "min_price": {
          "min": {
            "field": "resellers.price"
          }
        }
      }
    }
  }
}

As you can see above, the nested aggregation requires the path of the nested documents within the top level documents. Then one can define any type of aggregation over these nested documents.

Response:

{
  ...
  "aggregations": {
    "resellers": {
      "doc_count": 2,
      "min_price": {
        "value": 350.0
      }
    }
  }
}

You can use a filter sub-aggregation to return results for a specific reseller.

resp = client.search(
    index="products",
    size="0",
    query={
        "match": {
            "name": "led tv"
        }
    },
    aggs={
        "resellers": {
            "nested": {
                "path": "resellers"
            },
            "aggs": {
                "filter_reseller": {
                    "filter": {
                        "bool": {
                            "filter": [
                                {
                                    "term": {
                                        "resellers.reseller": "companyB"
                                    }
                                }
                            ]
                        }
                    },
                    "aggs": {
                        "min_price": {
                            "min": {
                                "field": "resellers.price"
                            }
                        }
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'products',
  size: 0,
  body: {
    query: {
      match: {
        name: 'led tv'
      }
    },
    aggregations: {
      resellers: {
        nested: {
          path: 'resellers'
        },
        aggregations: {
          filter_reseller: {
            filter: {
              bool: {
                filter: [
                  {
                    term: {
                      'resellers.reseller' => 'companyB'
                    }
                  }
                ]
              }
            },
            aggregations: {
              min_price: {
                min: {
                  field: 'resellers.price'
                }
              }
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "products",
  size: 0,
  query: {
    match: {
      name: "led tv",
    },
  },
  aggs: {
    resellers: {
      nested: {
        path: "resellers",
      },
      aggs: {
        filter_reseller: {
          filter: {
            bool: {
              filter: [
                {
                  term: {
                    "resellers.reseller": "companyB",
                  },
                },
              ],
            },
          },
          aggs: {
            min_price: {
              min: {
                field: "resellers.price",
              },
            },
          },
        },
      },
    },
  },
});
console.log(response);
GET /products/_search?size=0
{
  "query": {
    "match": {
      "name": "led tv"
    }
  },
  "aggs": {
    "resellers": {
      "nested": {
        "path": "resellers"
      },
      "aggs": {
        "filter_reseller": {
          "filter": {
            "bool": {
              "filter": [
                {
                  "term": {
                    "resellers.reseller": "companyB"
                  }
                }
              ]
            }
          },
          "aggs": {
            "min_price": {
              "min": {
                "field": "resellers.price"
              }
            }
          }
        }
      }
    }
  }
}

The search returns:

{
  ...
  "aggregations": {
    "resellers": {
      "doc_count": 2,
      "filter_reseller": {
        "doc_count": 1,
        "min_price": {
          "value": 500.0
        }
      }
    }
  }
}

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/search-aggregations-bucket-nested-aggregation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API