Обновить только определенный поддокумент глубоко во вложенном массиве массива документов

У меня есть образец документа с вложенными массивами, как показано ниже. {

"locations" : [ 
        {
                "appointments" : [ 
                {
                    "apptId" : "3456",
                    "status" : ""
                }, 
                {
                    "apptId" : "12345",
                    "status" : ""
                }
            ]
        }, 
        {
            "appointments" : [ 
                {
                    "apptId" : "12345",
                    "status" : ""
                }, 
                {
                    "apptId" : "3456",
                    "status" : ""
                }
            ]
        }
]

}

Я хотел бы обновить только тот поддокумент во вложенном массиве, который удовлетворяет моим критериям.

Я попытался использовать приведенный ниже запрос, но не могу обновить конкретный документ, который может находиться в любом индексе во вложенном массиве. Это дает мне нежелательные результаты.

Query query = new Query();      query.addCriteria(Criteria.where("locations.appointments.apptId").is(apptId));
Update update = new Update();
update.set("locations.$[].appointments.$.status", "cancelled");

WriteResult wrote = mongoTemplate.updateMulti(query, update, Schema.class, collectionName);

Мой ожидаемый результат - обновить статус 2-й встречи в первом месте и 1-й встречи во 2-м месте (т.е. критерии, соответствующие apptId = 12345) до «отменено». Я пытался использовать update.set("locations.$[].appointments.$.status", "cancelled"); и update.set("locations.$[].appointments.$[].status", "cancelled");, это просто не дало желаемого результата.

Пожалуйста, помогите мне с этим. Моя версия MongoDB — 3.6.10. Спасибо!


person Madhu Reddy    schedule 05.04.2019    source источник
comment
По сути, вам не хватает синтаксиса arrayFilters и $[<identifier>] с позиционной фильтрацией, поскольку позиционное all $[] просто обновляет ВСЕ элементы массива, а не только те критерии соответствия. Вместо этого у вас есть что-то вроде "locations.$[].appointments.$[elem].status", "cancelled" в качестве аргументов для $set и { "arrayFilters": [{ "elem.apptId": "3456" }] } или .filterArray(Criteria.where("elem.apptId").eq("3456")), которые теперь объединены в spring mongo. Обратите внимание, что если ваша версия весеннего монго еще не поддерживает это, вы всегда можете получить коллекцию из необработанного драйвера.   -  person Neil Lunn    schedule 07.04.2019
comment
Также обратите внимание, что позиционный фильтр $[<identifier>] и позиционный al $[] обновляют ВСЕ совпадения (или все). Если вы ожидали, что обновится только одно из совпадающих значений, вы должны включить уникальный идентификатор в "locations" и сделать что-то вроде $set: { "location.$[outer].appointments.$[inner].status": "cancelled" } и { "arrayFilters": [{ "outer._id": "uniqueId" },{ "inner.apptId": "3456" }] } или List из Criteria в зависимости от ситуации. Первый связанный дубликат объясняет, почему позиционный $ ненадежен даже для one с вложенным массивом.   -  person Neil Lunn    schedule 07.04.2019