Слияние во вложенный объект с помощью агрегации mongodb

#mongodb #aggregation-framework

Вопрос:

У меня есть коллекция MongoDB со структурой документа, аналогичной:

 {
    "_id" : "xxx",
    "inner : {
        "foo" : 1,
        "bar" : 2
    }
}
 

Версия базы данных 4.2.6

и конвейер агрегирования, предпоследний этап $project которого связан с итоговым документом, соответствующим чему-то подобному этому:

 {
    "_id" : "xxx",
    "inner : {
        "baz" : 3
    }
}
 

Затем следует заключительный этап для объединения в коллекцию:

 {
    "$merge" : {
        into: "myCollection",
        on: "_id",
        whenMatched: "merge",
        whenNotMatched: "discard"
    }
}
 

Однако в результате существующие inner поля документа переопределяются $merge результатами. Значение:

Ожидаемые результаты:

 {
    "_id" : "xxx",
    "inner : {
        "foo" : 1,
        "bar" : 2,
        "baz" : 3
    }
}
 

Фактические результаты:

 {
    "_id" : "xxx",
    "inner : {
        "baz" : 3
    }
}
 

Как я могу преодолеть это?

Ответ №1:

Опция «объединить» объединяет корневой документ, поэтому inner поле заменяется в вашем запросе.
попробуйте заменить слияние этим слиянием, использующим конвейер.
Я еще не тестировал его, но думаю, что все будет в порядке.
$$new переменная определяется монго для ссылки на документ, поступающий из конвейера.

 {
    "$merge" : {
        into: "myCollection",
        on: "_id",
        whenMatched: 
          [{"$project": 
             {"_id": "$_id",
              "inner": {"$mergeObjects": ["$inner","$new.inner"]}}}],
        whenNotMatched: "discard"
    }
}
 

Ответ №2:

Принятый ответ был хорошей зацепкой, хотя $project трубопровод привел к тому, что все поля, кроме _id и inner , были переопределены. Конечно, это не то, чего я хотел.

Что должно было быть очевидным выбором, так это просто использовать $addFields вместо этого:

  whenMatched:  [
     {"$addFields" :
         {"inner.baz": "$new.baz"}
     }
 ]