Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

elasticsearch:use script to update nested field?

I want to add a object into the nested field every update time.

For example,I have a doc:

{
    "test":[{"remark":"remark1"}]
}

Next time,i want to add a remark object into test field and save the old remark objects.And the result is :

{
    "test":[{"remark":"remark1"},{"remark":"remark2"}]
}

How to achieve it?

Edit I use the script:

{
    "script": "ctx._source.test= ((ctx._source.test?: []) += remarkItem)",
    "params": {
        "remarkItem": {
            "remark": "addd"
        }
    }
}

But,i get the exception:

{
"error": {
    "root_cause": [
        {
            "type": "remote_transport_exception",
            "reason": "[es77][10.14.84.77:9300][indices:data/write/update[s]]"
        }
    ],
    "type": "illegal_argument_exception",
    "reason": "failed to execute script",
    "caused_by": {
        "type": "script_exception",
        "reason": "Failed to compile inline script [ctx._source.test= ((ctx._source.test?: []) += remarkItem)] using lang [groovy]",
        "caused_by": {
            "type": "script_exception",
            "reason": "failed to compile groovy script",
            "caused_by": {
                "type": "multiple_compilation_errors_exception",
                "reason": "startup failed:\na8220b2cf14b8b7ebeead7f068416882d04fa25d: 1: \nclass org.codehaus.groovy.ast.expr.ElvisOperatorExpression, with its value '(ctx._source.test) ? ctx._source.test: []', is a bad expression as the left hand side of an assignment operator at line: 1 column: 82. File: a8220b2cf14b8b7ebeead7f068416882d04fa25d @ line 1, column 82.\n   CILastCallResultRemark ?: []) += remarkI\n                                 ^\n\n1 error\n"
            }
        }
    }
},
"status": 400
}

edit

Now,i want to add a field to ensure update or insert the object. For example:

{
    "test":[{"remark":"remark1","id":"1"}]
}

When i update the field,when the id exist,i will update the object.On the contrary,i will insert the object.

like image 321
Dev Zhou Avatar asked Apr 13 '16 06:04

Dev Zhou


1 Answers

I suggest to try a script like this, which takes two parameters in argument. It will check if any of the nested objects already contains the given id:

  • if yes, it will update the given remark
  • if not, it will insert a new nested object in the test array.

The script goes like this:

def updated = false
ctx._source.test?.each { obj -> 
    if (obj.id == item.id) { 
        obj.remark = item.remark
        updated = true
    } 
}
if (!updated) {
    ctx._source.test = ((ctx._source.test ?: []) + item)
}

After being inlined and with proper semicolons, the script looks like this:

{
    "script": "def updated = false; ctx._source.test?.each { obj -> if (obj.id == item.id) { obj.remark = item.remark; updated = true } }; if (!updated) { ctx._source.test = ((ctx._source.test ?: []) + item)}",
    "params": {
        "item": {
            "remark": "addd",
            "id": "1"
        }
    }
}
like image 81
Val Avatar answered Nov 13 '22 10:11

Val