How to set unique object ids in embedded documents across a MongoDB collection

MongoDB’s updateMany can be used to update all documents which are matched.

Problem

If, however, you want to set unique new ObjectIDs in your update, you would find that MongoDB sets the same ObjectID for every entry:

db.getCollection(‘mypis_collectedpis’).updateMany({}, {$set:
     {apps: {
         “com.picockpit/core”: {
             meta: {
                 version: “2.0”,
                 name: “PiCockpit Core”,
                 image: “”,
                 description: “PiCockpit.com core application”
                 }
             },
             id: ObjectId()
         },
      ts: ISODate(“2020-07-23T08:42:41.052Z”)}
    })

image

This is because the ObjectId is created once and then used for every update.

Solution

You need to iterate over the individual documents using a cursor, and to set the ObjectIDs.

First step

Update / set the values which will be the same across your documents.

I suggest setting the distinct values to null at first in this step already:

db.getCollection(‘mypis_collectedpis’).updateMany({}, {$set:
     {apps: {
         “com.picockpit/core”: {
             meta: {
                 version: “2.0”,
                 name: “PiCockpit Core”,
                 image: “”,
                 description: “PiCockpit.com core application”
                 }
             },
             id: null
         },
      ts: ISODate(“2020-07-23T08:42:41.052Z”)}
    })

image

NB: I use Robo 3T for a more comfortable experience than the MongoDB command line shell.

you will get:

image

Second step

Iterate across the documents, and update each using updateOne:

db.getCollection(‘mypis_collectedpis’).find().forEach((pi) => {
     print(“Updating” + pi.name + ” with ObjectId: ” + pi._id);
     db.getCollection(‘mypis_collectedpis’).updateOne({_id: pi._id}, {$set: {“apps.id”: ObjectId()}});
     })

image

note the dot notation for accessing entries in an embedded document – for the dot notation the item key has to be enclosed in quotation marks!

By the way this is the output this generates:

image

and this is the result, for two distinct entries:

image

image

The ObjectIDs have been updated with distinct values.

Important note

Note that in this code there are no locks / no transactions – for this solution to work, you would need to have exclusive access to the database, or ensure that the data is not changed while you’re working on the database.

Otherwise some kind of update scheme has to be put in place – an exercise left to the reader.

Thanks go to Maximilian Schwarzmüller for his Udemy MongoDB course, and the excellent MongoDB online documentation!