I have an index where one of the fields is a list of objects. I can't make each one its own field or the number of fields would explode.
Updates to the document come along as items to add or update one of the objects in the list. How can I craft an update to achieve this?
You can do this with scripts and update_by_query.
Let's create an index:
PUT test-index/_doc/1
{
"id": 3
}
After a new sub-document comes along we'd like it to look like this:
GET test-index/_doc/1
returns:
{
"id": 1,
"items": [{
"id": "q1",
"colour": "brown"
}]
}
We can do this by storing the following script and then invoking it:
POST _scripts/upsert_item_in_list
{
"script":{
"lang": "painless",
"source": """
if (ctx._source[params.field] == null) {
ctx._source[params.field] = [];
}
def items = ctx._source[params.field];
def index = -1;
for (int i = 0; i < items.length; i++)
{
if (items[i][params.key] == params.item[params.key])
{
index = i
}
}
if (index>=0) {
items[index] = params.item;
} else {
items.add(params.item)
}
"""
}
}
It takes three parameters:
We can invoke it as follows:
POST test-index/_update_by_query
{
"script":{
"params": {
"item": { "id": "q1", "colour": "brown" },
"field": "items",
"key": "id"
},
"id": "upsert_item_in_list"
},
"query":{
"match":{
"id": 1
}
}
}