2022-08-11 12:02:21 -04:00
---
layout: default
title: Join
nav_order: 43
has_children: false
parent: Object field types
grand_parent: Supported field types
2023-03-08 10:53:21 -05:00
redirect_from:
- /opensearch/supported-field-types/join/
2022-08-11 12:02:21 -04:00
---
# Join field type
A join field type establishes a parent/child relationship between documents in the same index.
## Example
Create a mapping to establish a parent-child relationship between products and their brands:
```json
2022-09-14 16:51:03 -04:00
PUT testindex1
2022-08-11 12:02:21 -04:00
{
"mappings": {
"properties": {
"product_to_brand": {
"type": "join",
"relations": {
"brand": "product"
}
}
}
}
}
```
2023-01-30 17:09:38 -05:00
{% include copy-curl.html %}
2022-08-11 12:02:21 -04:00
Then, index a parent document with a join field type:
```json
PUT testindex1/_doc/1
{
"name": "Brand 1",
"product_to_brand": {
"name": "brand"
}
}
```
2023-01-30 17:09:38 -05:00
{% include copy-curl.html %}
2022-08-11 12:02:21 -04:00
You can also use a shortcut without object notation to index a parent document:
```json
PUT testindex1/_doc/1
{
"name": "Brand 1",
"product_to_brand" : "brand"
}
```
2023-01-30 17:09:38 -05:00
{% include copy-curl.html %}
2022-08-11 12:02:21 -04:00
When indexing child documents, you have to specify the `routing` query parameter because parent and child documents in the same relation have to be indexed on the same shard. Each child document refers to its parent's ID in the `parent` field.
Index two child documents, one for each parent:
```json
PUT testindex1/_doc/3?routing=1
{
"name": "Product 1",
"product_to_brand": {
"name": "product",
"parent": "1"
}
}
2023-01-30 17:09:38 -05:00
```
{% include copy-curl.html %}
2022-08-11 12:02:21 -04:00
2023-01-30 17:09:38 -05:00
```json
2022-08-11 12:02:21 -04:00
PUT testindex1/_doc/4?routing=1
{
"name": "Product 2",
"product_to_brand": {
"name": "product",
"parent": "1"
}
}
```
2023-01-30 17:09:38 -05:00
{% include copy-curl.html %}
2022-08-11 12:02:21 -04:00
## Querying a join field
When you query a join field, the response contains subfields that specify whether the returned document is a parent or a child. For child objects, the parent ID is also returned.
### Search for all documents
```json
GET testindex1/_search
{
"query": {
"match_all": {}
}
}
```
2023-01-30 17:09:38 -05:00
{% include copy-curl.html %}
2022-08-11 12:02:21 -04:00
The response indicates whether a document is a parent or a child:
```json
{
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "testindex1",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "Brand 1",
"product_to_brand" : {
"name" : "brand"
}
}
},
{
"_index" : "testindex1",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.0,
"_routing" : "1",
"_source" : {
"name" : "Product 1",
"product_to_brand" : {
"name" : "product",
"parent" : "1"
}
}
},
{
"_index" : "testindex1",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.0,
"_routing" : "1",
"_source" : {
"name" : "Product 2",
"product_to_brand" : {
"name" : "product",
"parent" : "1"
}
}
}
]
}
}
```
### Search for all children of a parent
Find all products associated with Brand 1:
```json
GET testindex1/_search
{
"query" : {
"has_parent": {
"parent_type":"brand",
"query": {
"match" : {
"name": "Brand 1"
}
}
}
}
}
```
2023-01-30 17:09:38 -05:00
{% include copy-curl.html %}
2022-08-11 12:02:21 -04:00
The response contains Product 1 and Product 2, which are associated with Brand 1:
```json
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "testindex1",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.0,
"_routing" : "1",
"_source" : {
"name" : "Product 1",
"product_to_brand" : {
"name" : "product",
"parent" : "1"
}
}
},
{
"_index" : "testindex1",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.0,
"_routing" : "1",
"_source" : {
"name" : "Product 2",
"product_to_brand" : {
"name" : "product",
"parent" : "1"
}
}
}
]
}
}
```
### Search for the parent of a child
Find the parent of Product 1:
```json
GET testindex1/_search
{
"query" : {
"has_child": {
"type":"product",
"query": {
"match" : {
"name": "Product 1"
}
}
}
}
}
```
2023-01-30 17:09:38 -05:00
{% include copy-curl.html %}
2022-08-11 12:02:21 -04:00
The response returns Brand 1 as Product 1's parent:
```json
{
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "testindex1",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "Brand 1",
"product_to_brand" : {
"name" : "brand"
}
}
}
]
}
}
```
## Parent with many children
One parent can have many children. Create a mapping with multiple children:
```json
PUT testindex1
{
"mappings": {
"properties": {
"parent_to_child": {
"type": "join",
"relations": {
"parent": ["child 1", "child 2"]
}
}
}
}
}
```
2023-01-30 17:09:38 -05:00
{% include copy-curl.html %}
2022-08-11 12:02:21 -04:00
## Join field type notes
- There can only be one join field mapping in an index.
- You need to provide the routing parameter when retrieving, updating, or deleting a child document. This is because parent and child documents in the same relation have to be indexed on the same shard.
- Multiple parents are not supported.
- You can add a child document to an existing document only if the existing document is already marked as a parent.
- You can add a new relation to an existing join field.