'elasticsearch node.js API remove an object from an array on a document using painless script results in array Index Out of Bounds

I want to remove items (an object) from an array on a document in elasticsearch, however whenever I try and run my update script using painless, I receive an Array Index Out of Bounds exception.

I'm using the javascript elasticsearch npm package to search elasticsearch for the relevant documents which then returns me data like:

"_index": "centres",
"_type": "doc",
"_id": "51bc77d1-b514-4f4e-85fa-412def6829f5",
"_score": 1,
"_source": {
    "id": "cbaa7daa-f1a2-4ac3-8d7c-fc981245d21c",
    "name": "Five House",
    "openDays": [
        {
            "title": "new open Day",
            "endDate": "2022-03-22T00:00:00.000Z",
            "id": "82be934b-eeb1-419c-96ed-a58808b30df7"
        },
        {
            "title": "last open Day",
            "endDate": "2020-12-24T00:00:00.000Z",
            "id": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
        }
    ]
}

I then want to go through and remove certain items from the openDays array. I've created an array of the items I want to remove, so for the above example:

[
  {
    id: '51bc77d1-b514-4f4e-85fa-412def6829f5',
    indexes: [
        {
            "title": "last open Day",
            "endDate": "2020-12-24T00:00:00.000Z",
            "id": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
        }
    ]
  }
]

I'm then trying to run an update via the elasticsearch node client like this:

for (const centre of updates) {
    if (centre.indexes.length) {
        await Promise.all(centre.indexes.map(async (theIndex) => {
            const updated = await client.update({
                index: 'centres',
                type: 'doc',
                id: centre.id,
                body: {
                    script: {
                        lang: 'painless',
                        source: "ctx._source.openDays.remove(ctx._source.openDays.indexOf('openDayID'))",
                        params: {
                            "openDayID": theIndex.id
                        }
                    }
                }
            }).catch((err) => {throw err;});
        }))
            .catch((err) => {throw err;});

        await client.indices.refresh({ index: 'centres' }).catch((err) => { throw err;});
    }
}

When I run this though, it returns a 400 with an "array_index_out_of_bounds_exception" error:

  -> POST http://localhost:9200/centres/doc/51bc77d1-b514-4f4e-85fa-412def6829f5/_update
  {
    "script": {
      "lang": "painless",
      "source": "ctx._source.openDays.remove(ctx._source.openDays.indexOf(\u0027openDayID\u0027))",
      "params": {
        "openDayID": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
      }
    }
  }
  <- 400
  {
    "error": {
      "root_cause": [
        {
          "type": "remote_transport_exception",
          "reason": "[oSsa7mn][172.17.0.2:9300][indices:data/write/update[s]]"
        }
      ],
      "type": "illegal_argument_exception",
      "reason": "failed to execute script",
      "caused_by": {
        "type": "script_exception",
        "reason": "runtime error",
        "script_stack": [],
        "script": "ctx._source.openDays.remove(ctx._source.openDays.indexOf(\u0027openDayID\u0027))",
        "lang": "painless",
        "caused_by": {
          "type": "array_index_out_of_bounds_exception",
          "reason": null
        }
      }
    },
    "status": 400
  }

I'm not quite sure where I'm going wrong with this. Am I using the indexOf painless script correctly? Does indexOf allow for the searching of properties on objects in arrays?



Solution 1:[1]

'openDayID' should be params.openDayID

And use removeIf:

"ctx._source.openDays.removeIf(el -> (el.id == params.openDayID))"

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 JVS