1

I have an elasticsearch documents which contain nested objects within them, I want to be able to remove them via the java update api. Here is the code containing the script:

UpdateRequest updateRequest = new UpdateRequest(INDEX, "thread", String.valueOf(threadId));
    updateRequest.script("for (int i = 0; i < ctx._source.messages.size(); i++){if(ctx._source.messages[i]._message_id == " + messageId + ")" +
            "{ctx._source.messages.remove(i);i--;}}", ScriptService.ScriptType.INLINE);
    client.update(updateRequest).actionGet();

This is the mapping of my document:

{
  "thread_and_messages": {
    "mappings": {
      "thread": {
        "properties": {
          "messages": {
            "type": "nested",
            "include_in_parent": true,
            "properties": {
              "message_id": {
                "type": "string"
              },
              "message_nick": {
                "type": "string"
              },
              "message_text": {
                "type": "string"
              }
            }
          },
          "thread_id": {
            "type": "long"
          }
        }
      }
    }
  }
}

I'm not receiving any error messages, but when I run a query on the index to find that nested document it hasn't been removed. Could someone let me know what I am doing wrong?

1 Answer 1

2

Since message_id is a string your script needs to account for it and be modified like this (see the escaped double quotes around the message_id field). There is a second typo, in that your mapping declares a message_id field but you name it _message_id in your script:

"for (int i = 0; i < ctx._source.messages.size(); i++){if(ctx._source.messages[i].message_id == \"" + messageId + "\")"
                                                                                  ^             ^                  ^
                                                                                  |             |                  |
                                                                   no underscore here        add escaped double quotes

Finally also make sure that you have dynamic scripting enabled in your ES config

UPDATE

You can try a "groovy-er" way of removing elements from lists, i.e. no more for loop and if, just use the groovy power:

"ctx._source.messages.removeAll{ it.message_id == \"" + messageId + "\"}"

Normally, that will modify the messages array by removing all elements whose message_id field matches the messageId value.

Sign up to request clarification or add additional context in comments.

4 Comments

I've made those changes, yet it's still not removing the matching message_id. Here are my changes: UpdateRequest updateRequest = new UpdateRequest(INDEX, "thread", String.valueOf(threadId)); updateRequest.script("for (int i = 0; i < ctx._source.messages.size(); i++)" + "{if(ctx._source.messages[i].message_id == \"" + messageId + "\") ctx._source.messages.remove(i);}", ScriptService.ScriptType.INLINE); client.update(updateRequest).actionGet();
I've enabled scripting, just wondering, where does this normally go in the elasticsearch.yml file?
Yes, in the config file on each node, and then you can restart each node.
Is there any preattier solution in Elasticsearch 6.1 for deleting nested object in java? Dynamic scripting looks nasty. Like an antipattern of "NoSql injection".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.