0

I had to change one of the fields of my collection in mongoDB from an object to array of objects containing a lot of data. New documents get inserted without any problem, but when attempted to get old data, it never maps to the original DTO correctly and runs into errors.

subject is the field that was changed in Students collection.

I was wondering is there any way to update all the records so they all have the same data type, without losing any data.

The old version of Student:

{
    "_id": "5fb2ae251373a76ae58945df",
    "isActive": true,
    "details": {
      "picture": "http://placehold.it/32x32",
      "age": 17,
      "eyeColor": "green",
      "name": "Vasquez Sparks",
      "gender": "male",
      "email": "[email protected]",
      "phone": "+1 (962) 512-3196",
      "address": "619 Emerald Street, Nutrioso, Georgia, 6576"
    },
    "subject": 
      {
        "id": 0,
        "name": "math",
        "module": {
          "name": "Advanced",
          "semester": "second"
        }
      }
  }

This needs to be updated to the new version like this:

{
    "_id": "5fb2ae251373a76ae58945df",
    "isActive": true,
    "details": {
      "picture": "http://placehold.it/32x32",
      "age": 17,
      "eyeColor": "green",
      "name": "Vasquez Sparks",
      "gender": "male",
      "email": "[email protected]",
      "phone": "+1 (962) 512-3196",
      "address": "619 Emerald Street, Nutrioso, Georgia, 6576"
    },
    "subject": [
      {
        "id": 0,
        "name": "math",
        "module": {
          "name": "Advanced",
          "semester": "second"
        }
      },
      {
        "id": 1,
        "name": "history",
        "module": {
          "name": "Basic",
          "semester": "first"
        }
      },
      {
        "id": 2,
        "name": "English",
        "module": {
          "name": "Basic",
          "semester": "second"
        }
      }
    ]
  }

I understand there might be a way to rename old collection, create new and insert data based on old one in to new one. I was wondering for some direct way.

4
  • Something is awry here. student: ["idDetails":{...} is not a valid object. Do you mean student: [ {"idDetails": {...} } ]? I think the shape you might be trying to go for is more like this: student: { idDetails: { ... }, subject: [ {modulefld1:val, modulefl2:val}, {mf1:val, mf2:val} ] } Commented Nov 13, 2020 at 21:35
  • You can slice the array from the first to the last subject, or filter could work too. This can be easy depending on the real structure. But we need more data my friend Commented Nov 13, 2020 at 22:20
  • can you post a sample document from collection? Commented Nov 14, 2020 at 7:41
  • Sorry for the typo earlier, i have updated the sample document above, note there are many nested sub documents (fields ) under module, skipped those to keep it short here. @BuzzMoschetti; @Minsky; @wak786 Commented Nov 16, 2020 at 16:59

1 Answer 1

1

The goal is to turn subject into an array of 1 if it is not already an array, otherwise leave it alone. This will do the trick:

update args are (predicate, actions, options).

db.foo.update(
// Match only those docs where subject is an object (i.e. not turned into array):
{$expr: {$eq:[{$type:"$subject"},"object"]}},   

// Actions: set subject to be an array containing $subject.  You MUST use the pipeline version
// of the update actions to correctly substitute $subject in the expression!
[  {$set: {subject: ["$subject"] }} ],

// Do this for ALL matches, not just first:                  
{multi:true});

You can run this converter over and over because it will ignore converted docs.

If the goal is to convert and add some new subjects, preserving the first one, then we can set up the additional subjects and concatenate them into one array as follows:

var mmm = [ {id:8, name:"CORN"}, {id:9, name:"DOG"} ];

rc = db.foo.update({$expr: {$eq:[{$type:"$subject"},"object"]}},
                   [ {$set: {subject: {$concatArrays: [["$subject"], mmm]} }} ],
                   {multi:true});

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.