13

I have required to remove object from array that satisfies the condition, I am able to update the object of array on the basis of condition, which is as follow:

PUT twitter/twit/1
{"list": 
     [
        {
            "tweet_id": "1",
            "a": "b"
        },
        {
            "tweet_id": "123",
            "a": "f"
        }
    ]
}

POST /twitter/twit/1/_update
{"script":"foreach (item :ctx._source.list) {
                if item['tweet_id'] == tweet_id) {
                      item['new_field'] = 'ghi';
                }
           }",
 "params": {tweet_id": 123"}
}

this is working

for remove i am doing this

POST /twitter/twit/1/_update
{ "script": "foreach (item : ctx._source.list) {
                    if item['tweet_id'] == tweet_id) {
                          ctx._source.list.remove(item); 
                    }
            }",
  "params": { tweet_id": "123" }
}

but this is not working and giving this error,

ElasticsearchIllegalArgumentException[failed to execute script]; nested: ConcurrentModificationException; Error: ElasticsearchIllegalArgumentException[failed to execute script]; nested: ConcurrentModificationException

I am able to remove whole array or whole field using

"script": "ctx._source.remove('list')"

I am also able to remove object from array by specifying all the keys of an object using

"script":"ctx._source.list.remove(tag)",
     "params" : {
        "tag" : {"tweet_id": "123","a": "f"}

my node module elastic search version is 2.4.2 elastic search server is 1.3.2

2 Answers 2

20

You get that because you are trying to modify a list while iterating through it, meaning you want to change a list of object and, at the same time, listing those objects.

You instead need to do this:

POST /twitter/twit/1/_update
{
  "script": "item_to_remove = nil; foreach (item : ctx._source.list) { if (item['tweet_id'] == tweet_id) { item_to_remove=item; } } if (item_to_remove != nil) ctx._source.list.remove(item_to_remove);",
  "params": {"tweet_id": "123"}
}

If you have more than one item that matches the criteria, use a list instead:

POST /twitter/twit/1/_update
{
  "script": "items_to_remove = []; foreach (item : ctx._source.list) { if (item['tweet_id'] == tweet_id) { items_to_remove.add(item); } } foreach (item : items_to_remove) {ctx._source.list.remove(item);}",
  "params": {"tweet_id": "123"}
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks Andrei Stefan, This is working, if list contain only one object of tweet_id = 123, but This is not working , if I want to remove multiple object having same tweet_id = 123, What I have required to do for that???
Also, I would appreciate if you could upvote the answer.
Thank you very much Andrei Stefan, This is now working, after this I am very happy, as yesterday I have spend almost complete day on this , Thank you once again....
how can i know the list have ` remove` method, does it have append
9

For people that need this working in elasticsearch 2.0 and up, the nil and foreach don't get recognized by groovy.

So here's a updated version, including a option to replace a item with the same id by a new object.

and also passing it the upsert will make sure the item gets added even if the document doesn't exist yet

{
  "script": "item_to_remove = null; ctx._source.delivery.each { elem -> if (elem.id == item_to_add.id) { item_to_remove=elem; } }; if (item_to_remove != null) ctx._source.delivery.remove(item_to_remove); if (item_to_add.size() > 1) ctx._source.delivery += item_to_add;",
  "params": {"item_to_add": {"id": "5", "title": "New item"}},
  "upsert": [{"id": "5", "title": "New item"}]
}

1 Comment

Can you please also add in groove language to remove more than one values as list instead of single remove?

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.