简体   繁体   中英

Need your help for a MongoDb Migration to add fields to randomly named nested objects. `connections: { [id: string]: some_object_type }`

Need some real help on this! And only you can help me!

Currently writing a MongoDb migration and I'm required to add some new fields to a nested object of unknown field name

Example of document:

{
        "_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,
                        }
                }
        }
}

Given this document, where connections: { [id: string]: some_object_type }

Note that :

some_object_type: {
  some_field_1: string,
  some_field_2: sub_object_type
}

and

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

Have tried using $[] which has worked for other collections in the same migration script. Sadly, $ is not of much help, given that its usage is limited to arrays.

My current train of thought has led me to believe that the right approach lays in the evaluation query operator $where , in order to isolate the randomly named id : string object field

Long story short... looking for an alternative to the $[] operator to use with objects

The updated document will look like this:

{
        "_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
                        }
                }
        }
}

You can get desired result in 2 ways:

Shell JS: We can execute JS code with recursive function:

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))
})

Aggregation: With $objectToArray we normalize connection into key:value array.

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

We go down till sub_object_type field and add new new_sub_field field with $mergeObjects . To convert normalized array into object, we use $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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM