Nested field type

Introduced 1.0

A nested field type is a special type of object field type.

Any object field can take an array of objects. Each of the objects in the array is dynamically mapped as an object field type and stored in flattened form. This means that the objects in the array are broken down into individual fields, and values for each field across all objects are stored together. It is sometimes necessary to use the nested type to preserve a nested object as a whole so that you can perform a search on it.

Flattened form

By default, each of the nested objects is dynamically mapped as object field type. Any object field can take an array of objects.

  1. PUT testindex1/_doc/100
  2. {
  3. "patients": [
  4. {"name" : "John Doe", "age" : 56, "smoker" : true},
  5. {"name" : "Mary Major", "age" : 85, "smoker" : false}
  6. ]
  7. }

copy

When these objects are stored, they are flattened, so their internal representation has an array of all values for each field:

  1. {
  2. "patients.name" : ["John Doe", "Mary Major"],
  3. "patients.age" : [56, 85],
  4. "patients.smoker" : [true, false]
  5. }

Some queries will work correctly in this representation. If you search for patients older than 75 OR smokers, document 100 should match.

  1. GET testindex1/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "should": [
  6. {
  7. "term": {
  8. "patients.smoker": true
  9. }
  10. },
  11. {
  12. "range": {
  13. "patients.age": {
  14. "gte": 75
  15. }
  16. }
  17. }
  18. ]
  19. }
  20. }
  21. }

copy

The query correctly returns document 100:

  1. {
  2. "took" : 3,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 1,
  13. "relation" : "eq"
  14. },
  15. "max_score" : 1.3616575,
  16. "hits" : [
  17. {
  18. "_index" : "testindex1",
  19. "_type" : "_doc",
  20. "_id" : "100",
  21. "_score" : 1.3616575,
  22. "_source" : {
  23. "patients" : [
  24. {
  25. "name" : "John Doe",
  26. "age" : "56",
  27. "smoker" : true
  28. },
  29. {
  30. "name" : "Mary Major",
  31. "age" : "85",
  32. "smoker" : false
  33. }
  34. ]
  35. }
  36. }
  37. ]
  38. }
  39. }

Alternatively, if you search for patients older than 75 AND smokers, document 100 should not match.

  1. GET testindex1/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "must": [
  6. {
  7. "term": {
  8. "patients.smoker": true
  9. }
  10. },
  11. {
  12. "range": {
  13. "patients.age": {
  14. "gte": 75
  15. }
  16. }
  17. }
  18. ]
  19. }
  20. }
  21. }

copy

However, this query still incorrectly returns document 100. This is because the relation between age and smoking was lost when arrays of values for individual fields were created.

Nested field type

Nested objects are stored as separate documents, and the parent object has references to its children. To mark objects as nested, create a mapping with a nested field type.

  1. PUT testindex1
  2. {
  3. "mappings" : {
  4. "properties": {
  5. "patients": {
  6. "type" : "nested"
  7. }
  8. }
  9. }
  10. }

copy

Then, index a document with a nested field type:

  1. PUT testindex1/_doc/100
  2. {
  3. "patients": [
  4. {"name" : "John Doe", "age" : 56, "smoker" : true},
  5. {"name" : "Mary Major", "age" : 85, "smoker" : false}
  6. ]
  7. }

copy

You can use the following nested query to search for patients older than 75 OR smokers:

  1. GET testindex1/_search
  2. {
  3. "query": {
  4. "nested": {
  5. "path": "patients",
  6. "query": {
  7. "bool": {
  8. "should": [
  9. {
  10. "term": {
  11. "patients.smoker": true
  12. }
  13. },
  14. {
  15. "range": {
  16. "patients.age": {
  17. "gte": 75
  18. }
  19. }
  20. }
  21. ]
  22. }
  23. }
  24. }
  25. }
  26. }

copy

The query correctly returns both patients:

  1. {
  2. "took" : 7,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 1,
  13. "relation" : "eq"
  14. },
  15. "max_score" : 0.8465736,
  16. "hits" : [
  17. {
  18. "_index" : "testindex1",
  19. "_id" : "100",
  20. "_score" : 0.8465736,
  21. "_source" : {
  22. "patients" : [
  23. {
  24. "name" : "John Doe",
  25. "age" : 56,
  26. "smoker" : true
  27. },
  28. {
  29. "name" : "Mary Major",
  30. "age" : 85,
  31. "smoker" : false
  32. }
  33. ]
  34. }
  35. }
  36. ]
  37. }
  38. }

You can use the following nested query to search for patients older than 75 AND smokers:

  1. GET testindex1/_search
  2. {
  3. "query": {
  4. "nested": {
  5. "path": "patients",
  6. "query": {
  7. "bool": {
  8. "must": [
  9. {
  10. "term": {
  11. "patients.smoker": true
  12. }
  13. },
  14. {
  15. "range": {
  16. "patients.age": {
  17. "gte": 75
  18. }
  19. }
  20. }
  21. ]
  22. }
  23. }
  24. }
  25. }
  26. }

copy

The previous query returns no results, as expected:

  1. {
  2. "took" : 7,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 0,
  13. "relation" : "eq"
  14. },
  15. "max_score" : null,
  16. "hits" : [ ]
  17. }
  18. }

Parameters

The following table lists the parameters accepted by object field types. All parameters are optional.

ParameterDescription
dynamicSpecifies whether new fields can be dynamically added to the object. Valid values are true, false, strict, and strict_allow_templates. Default is true.
include_in_parentA Boolean value that specifies whether all fields in the child nested object should also be added to the parent document in flattened form. Default is false.
include_in_rootA Boolean value that specifies whether all fields in the child nested object should also be added to the root document in flattened form. Default is false.
propertiesFields of this object, which can be of any supported type. New properties can be dynamically added to this object if dynamic is set to true.

Next steps