Нужна ваша помощь для миграции MongoDb, чтобы добавить поля к случайно названным вложенным объектам. `connections: {[id: string]: some_object_type}` - PullRequest
0 голосов
/ 29 января 2020

Нужна реальная помощь в этом! И только вы можете помочь мне!

В настоящее время пишу миграцию MongoDb, и мне необходимо добавить несколько новых полей во вложенный объект с неизвестным именем поля

Пример документа:

{
        "_id" : "1a3a5c0c-4542-4bcc-9965-5c04db8d3edc",
        "name" : "Test_person",
        "connections" : {
                "540e1234-field_random_num" : {
                        "some_field_1" : "Garbage_string_1",
                        "some_field_2" : {
                                "sub_field_1" : 1234,
                                "sub_field_2" : 5678,
                                "sub_field_3" : null,
                        }
                },
                "48925678-field_random_num_2" : {
                        "some_field_1" : "Garbage_string_2",
                        "some_field_2" : {
                                "sub_field_1" : 4321,
                                "sub_field_2" : 8765,
                                "sub_field_3" : null,
                        }
                }
        }
}

Учитывая этот документ, где connections: { [id: string]: some_object_type }

Обратите внимание, что:

some_object_type: {
  some_field_1: string,
  some_field_2: sub_object_type
}

и

sub_object_type: {
  "sub_field_1" : number
  "sub_field_1" : number
  "sub_field_1" : string
}

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

Мой текущий ход мыслей заставил меня поверить, что правильный подход лежит в операторе оценочного запроса $where, чтобы изолировать произвольно названное id : string поле объекта

Короче говоря ... ищет альтернативу оператору $[] для использования с объектами

Обновленный документ будет выглядеть так:

{
        "_id" : "1a3a5c0c-4542-4bcc-9965-5c04db8d3edc",
        "name" : "Test_person",
        "connections" : {
                "540e1234-field_random_num" : {
                        "some_field_1" : "Garbage_string_1,
                        "some_field_2" : {
                                "sub_field_1" : 1234,
                                "sub_field_2" : 5678,
                                "sub_field_3" : null,
                                "new_sub_field" : null <-- new field
                        }
                },
                "48925678-field_random_num_2" : {
                        "some_field_1" : "Garbage_string_2",
                        "some_field_2" : {
                                "sub_field_1" : 4321,
                                "sub_field_2" : 8765,
                                "sub_field_3" : null,
                                "new_sub_field" : null <-- new field
                        }
                }
        }
}

1 Ответ

0 голосов
/ 29 января 2020

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

Оболочка JS: Мы можем выполнить JS код с рекурсивной функцией:

db.collection.find({}).forEach(function(doc){
    function _(obj){
        //Iterate
        for(var key in obj){
            //If key is some_field_2, we insert inside new key:value
            if(key == "some_field_2"){
                obj[key]["new_sub_field"] = null;

            // If value is object, we call recursive function
            } else if (typeof(obj[key]) == "object"){
                obj[key] = _(obj[key]);
            }
        }
        return obj;
    }

    print(_(doc))
})

Агрегирование: С помощью $ objectToArray мы нормализуем connection в key:value массив.

We convert 
{"connection": {"foo":"bar", "buz" : "foobar"}}
into
{"connection": [{"k":"foo", "v":"bar"}, {"k":"buz", "v":"foobar"}]}`

Мы go до sub_object_type поля и добавляем новое new_sub_field поле с $mergeObjects. Для преобразования нормализованного массива в объект мы используем $arrayToObject


db.collection.aggregate([
  {
    $project: {
      _id: 1,
      name: 1,
      connections: {
        $arrayToObject: {
          $map: {
            input: {
              $objectToArray: "$connections"
            },
            as: "conn",
            in: {
              k: "$$conn.k",
              v: {
                $arrayToObject: {
                  $map: {
                    input: {
                      $objectToArray: "$$conn.v"
                    },
                    as: "some_field",
                    in: {
                      k: "$$some_field.k",
                      v: {
                        $cond: [
                          {
                            $eq: [
                              "$$some_field.k",
                              "some_field_2"
                            ]
                          },
                          {
                            $mergeObjects: [
                              "$$some_field.v",
                              {
                                "new_sub_field": null
                              }
                            ]
                          },
                          "$$some_field.v"
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
])

MongoPlayground

...