Reputation: 532
"_source": {
"id": "5b1676493d21784208c36041",
"label": "name",
"properties": {
"name": "patrick"
},
"updatedAt": 1528259039542
}
I want to update this document based on id
(not _id
) with a new document.
Something like this:
"_source": {
"dataSource": "ELASTIC",
"entity": "vertices",
"label": "vertices",
"id": "5b1676493d21784208c36041",
"properties": {
"name": "patrick"
},
"updatedAt": 1528259039542
}
elasticsearch version: 6.2, ES Java api: 6.2
Upvotes: 2
Views: 4763
Reputation: 4020
Thanks @jetnet for providing an idea to loop through all the entries in the map. When I used the script, it was still replacing the entire object, so had to adapt it as per the below to preserve the fields not supplied during an update operation. For context, if I first insert a document that has three objects each with 2 fields, if I then updated that document with the same 3 objects, but with 1 field each, the output is that I end up with a document with 3 objects each with 1 field instead of 3 objects with 2 fields each as I had originally.
I had to adapt @jetnet's script to give me the desired outcome of not overwriting object properties
POST /transaction_index/_update/33384637-3137-3132-5543-31304c4c3151
{
"script": {
"source": "if (ctx._source.Metadata == null || params.Metadata.Version >= ctx._source.Metadata.Version) { for (k in params.keySet()){ if (ctx._source[k] != null) { ctx._source[k].putAll(params.get(k)) } else { ctx._source.put(k, params.get(k)) } } } else { ctx.op = 'none' }",
"params": {
"Transaction": {
"TransactionId": "33384637-3137-3132-5543-31304c4c3151",
"TransactionKey": "Key1"
},
"Message": {
"MessageId": "505a5953-374a-385a-4a48-52353549445a",
"Context": "This is a test context"
},
"MessageDefinition": {
"MessageDefinitionId": "a1c05e06-fa6b-40ce-992f-d083ff6c0243",
"Code": 1010101010
},
"Metadata": {
"Version": 1,
"CreateTime": "2020-09-04T14:27:51.1986439+01:00",
"IsLatest": true,
"IsDummy": false,
"VersionString": "20200903111111"
}
}
},
"scripted_upsert": true,
"upsert": {}
}
Upvotes: 0
Reputation: 661
"ctx._source.putAll(params)"
was a nice try, but unfortunately it moves all existing fields under _source.ctx
.
So, the following works for me (ES 6.1):
"for (k in params.keySet()){if (!k.equals('ctx')){ctx._source.put(k, params.get(k))}}"
Upvotes: 1
Reputation: 217304
You can achieve what you want using the update by query API, basically like this:
POST index/_update_by_query
{
"query": {
"match": {
"id": "5b1676493d21784208c36041"
}
},
"script": {
"source": "ctx._source = params",
"params": {
"dataSource": "ELASTIC",
"entity": "vertices",
"label": "vertices"
}
}
}
UPDATE: Using the Java API
Map<String, String> params = new HashMap<>();
params.put("dataSource", "ELASTIC");
params.put("entity", "vertices");
params.put("label", "vertices");
UpdateByQueryRequestBuilder updateByQuery = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);
updateByQuery.source("index")
.filter(QueryBuilders.matchQuery("id", "5b1676493d21784208c36041"))
.size(1000)
.script(new Script(ScriptType.INLINE, "painless", "ctx._source.putAll(params)", params));
BulkByScrollResponse response = updateByQuery.get();
More details on using the UpdateByQuery Java API and Java high level rest client
Upvotes: 6