Home > Software design >  How to update nested numeric field value in Elasticsearch/ AWS Opensearch?
How to update nested numeric field value in Elasticsearch/ AWS Opensearch?

Time:11-13

I am not too familiar with ES, so perhaps I am making some mistakes.

I have an index users with the following mapping.

{
   "mappings":{
      "dynamic":false,
      "properties":{
         "id":{
            "type":"keyword"
         },
         "userId":{
            "type":"text"
         },
         "total":{
            "type":"float"
         },
         "count":{
            "type":"float"
         },
         "earnings":{
            "properties":{
               "potential":{
                  "properties":{
                     "pending":{
                        "type":"float"
                     },
                     "finished":{
                        "type":"float"
                     }
                  }
               },
               "completed":{
                  "properties":{
                     "pending":{
                        "type":"float"
                     },
                     "paid":{
                        "type":"float"
                     }
                  }
               }
            }
         }
      }
   }
}

I would like to update the nested fields such as earnings.potential.pending using Update API. I have a script similar to below using Update API.

{
  "script" : {
    "source": "ctx._source.earnings.potential.pending  = params.total",
    "lang": "painless",
    "params" : {
      "total" : 4
    }
  }
}


However, I encouter illegal_argument_exception, with the dot notations being the supposed issue as below.

"ctx._source.earnings.potential.pending  = params.total",
            ^---- HERE'

CodePudding user response:

If earnings is null on the document you are trying to update, you will get an error:

...
"caused_by": {
  "type": "null_pointer_exception",
  "reason": "cannot access method/field [potential] from a null def reference"
}

So in essence you need to set a default value on the field, if it is null. The easiest way would be to do it at indexing time, or run a one-time query to set the default value everywhere. But if it's not an option, you could extend your script to check and assign a default:

{
    "script": {
        "lang": "painless",
        "source": "if(ctx._source.earnings == null) { ctx._source.earnings = [:] }\n if(ctx._source.earnings.potential == null) { ctx._source.earnings.potential = [:] }\n if(ctx._source.earnings.potential.pending == null) { ctx._source.earnings.potential.pending = 0 } \n ctx._source.earnings.potential.pending  = params.total",
        "params": {
            "total": 5
        }
    }
}
  • Related