Обновите элемент в sub sub-массива в mongodb

У меня есть эти данные в Mongo:

{
    "_id" : ObjectId("505fd43fdbed3dd93f0ae088"),
    "categoryName" : "Cat 1",
    "services" : [
        {
            "serviceName" : "Svc 1",
            "input" : [
                { "quantity" : 10, "note" : "quantity = 10" }, 
                { "quantity" : 20, "note" : "quantity = 20" }
            ]
        },
        {
            "serviceName" : "Svc 2",
            "input" : [
                { "quantity" : 30, "note" : "quantity = 30" }, 
                { "quantity" : 40, "note" : "quantity = 40" }
            ]
        }
    ]
}

Теперь я хочу обновить количество для "Svc 1":

{ "quantity" : 10, "note" : "quantity = 10" }

Как

{"quantity": 100, "note": "changed to 100"}

Как я могу сделать с Mongo? `

Как я знаю, операционный оператор поддерживает только первый массив, кто-то посоветовал использовать индекс элемента вспомогательного массива, но проблема в том, что как знать этот индекс во время выполнения? (Я использую собственный драйвер С# для MongoDB)

Заранее благодарим за помощь!

Джонни

Ответ 1

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

Итак, например, вы можете обновить первый вход для "Svc 1" с эквивалентом С#:

db.services.update(

    // Criteria
    {
        '_id' : ObjectId("505fd43fdbed3dd93f0ae088"),
        'services.serviceName' : 'Svc 1'
    },

    // Updates
    {
        $set : {
            'services.$.input.0.quantity' : 100,
            'services.$.input.0.note' : 'Quantity updated to 100'
        }
    }
)

Если вы не знаете позицию для вложенного массива input, вам нужно будет выбрать соответствующий services, перебрать массив input в код приложения, а затем $set обновленный массив.

В качестве альтернативы вы можете изменить свой вложенный массив для использования встроенного документа, например:

{
    "categoryName" : "Cat 1",
    "services" : [
        {
            "serviceName" : "Svc 1",
            "input1" : { "quantity" : 10, "note" : "quantity = 10" }, 
            "input2" : { "quantity" : 20, "note" : "quantity = 20" }
        },
    ]
}

Что вы могли бы затем обновить по имени, например input1:

db.services.update(

    // Criteria
    {
        '_id' : ObjectId("5063e80a275c457549de2362"),
        'services.serviceName' : 'Svc 1'
    },

    // Updates
    {
        $set : {
            'services.$.input1.quantity' : 100,
            'services.$.input1.note' : 'Quantity updated to 100'
        }
    }
)

Ответ 2

Поскольку вы не знаете позицию значения, которое хотите обновить, сначала вставьте новое значение с обновленной информацией, а затем удалите значение, которое требуется обновить.

db.services.update(
   {
    '_id' : ObjectId("505fd43fdbed3dd93f0ae088"),
    'services.serviceName' : 'Svc 1'
   },
   {
    { $addToSet: { 'services.$.input' : "new sub-Doc" }
   }
)

И затем удалите, когда вставка успешна

db.services.update(
   {
    '_id' : ObjectId("505fd43fdbed3dd93f0ae088"),
    'services.serviceName' : 'Svc 1'
   },
   {
    { $pull: { 'services.$.input' : { "quantity" : 10, "note" : "quantity = 10" } }
   }
)

Это полезно, когда индекс неизвестен, и документ должен иметь поддокументы, имеющие тот же ключ, что и "enter" в post Обновить элемент в sub подмассива в mongodb