1

I have some data stored in my MongoDB. The "tags" fields is actually an array of Strings, but we have to update our model to store more data with those tags

Current model document

{
    "id" : "59e4aefd74f12800019ba565",
    "title" : "This is a title",
    "tags" : [ 
        "59b02e6f6b28ce0001f8c0a8", 
        "59b031886b28ce0001f8c0af", 
        "59ba8c1a5047570001a3c078"
    ]
}

Desired model after update

{
    "id" : "59e4aefd74f12800019ba565",
    "title" : "This is a title",
    "tags" : [ 
        {
            "id" : "5a82ff1d889a15000103b115",
            "internalName" : "Día Mundial de la Television"
        }, 
        {
            "id" : "59ba8c1a5047570001a3c078",
            "internalName" : "menu"
        }, 
        {
            "id" : "5a26ac73d0fc2e00017f286e",
            "internalName" : "oid_asdf_asd"
        }
    ],


}

Now tags is a embedded object (forget about internalName field). How can I update the tag field without losing those data? I've tried with $rename, but it doesn't work well with arrays

db.test.update({}, {$rename: {'tags': 'tags2.id'}})

1 Answer 1

1

Using the concepts from this very good answer, you could create a cursor from an aggregate operation that transforms the tags arrays by using the $map operator, iterate the cursor and update your collection using bulkWrite. The aggregate operation follows:

var cursor = db.test.aggregate([
    {
        "$project": {
            "tags": {
                "$map": {
                    "input": "$tags",
                    "as": "el",
                    "in": { 
                        "id": "$$el",
                        "internalName": { "$literal": "temp string" }
                    }
                }
            }
        }
    }
]);

And running the bulk update:

var bulkUpdateOps = [];

cursor.forEach(doc => {
    const { _id, tags } = doc;
    bulkUpdateOps.push({
        "updateOne": {
           "filter": { _id },
           "update": { "$set": { tags } },
           "upsert": true
        }
    });

    if (bulkUpdateOps.length === 1000) {
        db.test.bulkWrite(bulkUpdateOps);  
        bulkUpdateOps = [];                 
    }
}); 

if (bulkUpdateOps.length > 0) {
    db.test.bulkWrite(bulkUpdateOps);
}
Sign up to request clarification or add additional context in comments.

4 Comments

thanks for the reply. I'm testing it right now but it doesn't seems to works. (My bad probably). I'm trying to figure out why.
@dragonalvaro There was a typo in the code which I removed, try again
Now it worked! Thank you very much. I really appreciate your time.
Just one more correction, move the first if condition check into the forEach loop for it to work correctly i.e. execute the bulk updfate in batches of 1000. I have updated my answer to reflect this.

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.