How to update Nested Document in OpenSearch using UpdateRequest Java API?

Hi OpenSearch Team,

I have an index ‘person-car-index’ with the below document having _id: “p-123”

{
          "name" : "Andreas",
          "cars" : [
            {
              "model" : "Artura",
              "manufacturer" : "McLaren"
            },
            {
              "model" : "765LT",
              "manufacturer" : "McLaren"
            },
            {
              "model" : "SLS AMG Black Series",
              "manufacturer" : "Mercedes Benz"
            }
          ]
        }

And, here is the mapping for the same:

"mappings": {
    "properties": {
        "name": {
          "type": "text"
        },
        "cars": {
          "type": "nested",
          "properties": {
            "model": {
              "type": "text"
            },
            "manufacturer": {
              "type": "text"
            }
          }
        }
      }
  }

Now, I want to

  1. Add another car object in the cars array. (Say:
           {
              "model" : "720S",
              "manufacturer" : "McLaren"
            }
  1. Add a new attribute called “power” in the car object having “model”: “765LT”

How can I do that using UpdateRequest Java API ?

Note: I have tried the below for adding a new car object to existing “cars” array, but it just replaces the entire array with the new car object.
Here is my Java code:

                        XContentBuilder jb = XContentFactory.jsonBuilder();

			jb.startObject() // person
			.field("age", 46); // new root attribute "age"
			jb.startArray("cars"); // cars

			jb.startObject() // a car
					.field("model", "720S") // model
					.field("manufacturer", "McLaren") // manufacturer
			.endObject();

			jb.endArray();// cars
			
			jb.endObject();// person

			final UpdateRequest productVariantOptionsUpdateRequest = new UpdateRequest("person-car-index", "p-123")
					.doc(jb);

			bulkInsertProcessor.add(productVariantOptionsUpdateRequest);

Also Note: Update using Script works fine.

POST person-car-index/_doc/p-123/_update
{
  "script": {
    "source": """
        for(key in params.keySet()){
            boolean found = false;
        	for (int i=0; i<ctx._source.cars.size(); i++){
        		if (ctx._source.cars[i].model == key){
        			for(entry in params[key].entrySet()){
        				ctx._source.cars[i][entry.getKey()] = entry.getValue();
        				found = true;
        			}
        			break;
        		}
        	}
        	if(!found){
        		ctx._source.cars.add(params[key]);	
        	}
        }
    """,
    "params": {
      "765LT": {
        "power": "765 BHP"
      },
      "720S": {
        "model": "720S", 
        "manufacturer": "McLaren"
      }
    }
  }
}

Hi @Arijit ,

AFAIK, there is no way to make UpdateRequest work with nested arrays unless you use script for it (similar to what you have used with curl):

final UpdateRequest productVariantOptionsUpdateRequest = 
    new UpdateRequest("person-car-index", "p-123")
        .script( /* your script here */ )

Hope it helps.

2 Likes

Thanks for confirming @reta .