Children
The children
aggregation is a bucket aggregation that creates a single bucket containing child documents, based on parent-child relationships defined in your index.
The children
aggregation works with the join field type to aggregate child documents that are associated with parent documents.
The children
aggregation identifies child documents that match specific child relation name, whereas the parent
aggregation identifies parent documents that have matching child documents. Both aggregations take the child relation name as input.
Parameters
The children
aggregation takes the following parameters.
Parameter | Required/Optional | Data type | Description |
---|---|---|---|
type | Required | String | The name of the child type from the join field. This identifies the parent-child relationship to use. |
Example
The following example builds a small company database with three employees. The employee records each have a child join
relationship with a parent department record.
First, create a company
index with a join
field that maps departments (parents) to employees (children):
PUT /company
{
"mappings": {
"properties": {
"join_field": {
"type": "join",
"relations": {
"department": "employee"
}
},
"department_name": {
"type": "keyword"
},
"employee_name": {
"type": "keyword"
},
"salary": {
"type": "double"
},
"hire_date": {
"type": "date"
}
}
}
}
Next, populate the data with three departments and three employees. The parent-child assignments are presented in the following table.
Department (parent) | Employees (children) |
---|---|
Accounting | Abel Anderson , Betty Billings |
Engineering | Carl Carter |
HR | none |
The routing
parameter ensures that both parent and child documents are stored on the same shard, which is required in order for parent-child relationships to function correctly in OpenSearch:
POST _bulk?routing=1
{ "create": { "_index": "company", "_id": "1" } }
{ "type": "department", "department_name": "Accounting", "join_field": "department" }
{ "create": { "_index": "company", "_id": "2" } }
{ "type": "department", "department_name": "Engineering", "join_field": "department" }
{ "create": { "_index": "company", "_id": "3" } }
{ "type": "department", "department_name": "HR", "join_field": "department" }
{ "create": { "_index": "company", "_id": "4" } }
{ "type": "employee", "employee_name": "Abel Anderson", "salary": 120000, "hire_date": "2024-04-04", "join_field": { "name": "employee", "parent": "1" } }
{ "create": { "_index": "company", "_id": "5" } }
{ "type": "employee", "employee_name": "Betty Billings", "salary": 140000, "hire_date": "2023-05-05", "join_field": { "name": "employee", "parent": "1" } }
{ "create": { "_index": "company", "_id": "6" } }
{ "type": "employee", "employee_name": "Carl Carter", "salary": 140000, "hire_date": "2020-06-06", "join_field": { "name": "employee", "parent": "2" } }
The following request queries all the departments and then filters for the one named Accounting
. It then uses the children
aggregation to select the two documents that have a child relationship with the Accounting
department. Finally, the avg
subaggregation returns the average of the Accounting
employees’ salaries:
GET /company/_search
{
"size": 0,
"query": {
"bool": {
"filter": [
{
"term": {
"join_field": "department"
}
},
{
"term": {
"department_name": "Accounting"
}
}
]
}
},
"aggs": {
"acc_employees": {
"children": {
"type": "employee"
},
"aggs": {
"avg_salary": {
"avg": {
"field": "salary"
}
}
}
}
}
}
Example response
The response returns the selected department bucket, finds the employee
type children of the department, and computes the avg
of their salaries:
{
"took": 379,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"acc_employees": {
"doc_count": 2,
"avg_salary": {
"value": 110000
}
}
}
}