Nested documents are powerful because you retain certain attribute connections but there’s the downside of not being able to iterate over them as discussed here.
With that being said you could flatten the users
attributes using the copy_to
feature like so:
PUT my-index-000001
{
"mappings": {
"properties": {
"user__first_flattened": {
"type": "keyword"
},
"user": {
"type": "nested",
"properties": {
"first": {
"type": "keyword",
"copy_to": "user__first_flattened"
}
}
}
}
}
}
Then
PUT my-index-000001/_doc/1
{
"group": "fans",
"user": [
{
"first": "John",
"last": "Smith"
},
{
"first": "Alice",
"last": "White"
}
]
}
Now you’ve got access to the field values and can iterate over them (and possibly use the loop index to help locate/identify the correct ‘nested’ subdocument, if needed.) This only works under the assumption that you iterate over the field that’s represented in each nested subdocument so that your loop is not cut short:
GET my-index-000001/_search
{
"query": {
"bool": {
"filter": [
{
"script": {
"script": {
"inline": """
def users = doc.user__first_flattened;
// users == [Alice, John]
for ( int i = 0; i < users.size(); i++ ) {
}
return true;
"""
}
}
}
]
}
}
}
Notice that we’re not doing a nested
query anymore b/c we’re outside of that context and got our flattened field available in the root.
It’s also worth knowing that you can replace copy_to
with include_in_root
which is equally useful here.