Generate Unique IDs for Nested Arrays in MongoDB using Node.js

Kushagra Kesav
CodeX
Published in
3 min readApr 25, 2023
Nested JSON Objects

When working with MongoDB, you might find yourself dealing with complex documents that contain nested arrays of data. In some cases, you might need to generate unique identifiers for the elements in these arrays, so that you can easily reference them and perform operations on them.

In this article, we will explore how to generate unique IDs (ObjectId) for nested arrays in MongoDB using Node.js and the MongoDB driver.

To follow along with this tutorial, you will need to have the following installed on your computer:

  • Node.js
  • MongoDB
  • The MongoDB driver for Node.js (you can install this using the npm package manager) npm install mongodb

Once you have these dependencies installed, you can start writing the code.

Creating the Document

Let’s start by creating a sample document that we can use to demonstrate how to generate unique IDs for elements in nested arrays. Here’s an example of what the document might look like:

{
"_id": ObjectId("6141d4ea6af92531f3e174e1"),
"property": "value",
"pets": [
{
"dogs": [
{ "name": "Rufus" },
{ "name": "Buddy" }
],
"cats": [
{ "name": "Whiskers" },
{ "name": "Fluffy" }
]
}
]
}

This document has an _id field, a property field, and a nested array of pets. Each pet has its own nested array of dogs and cats, which we will use to generate unique IDs.

Generating Unique IDs

Now that we have our sample document, let’s write the query/code to generate unique IDs for the elements in the dogs and cats arrays.

To generate unique IDs, we first attempted to use an update query in the mongo shell

db.a.updateMany(
{ animals: { $ne: [] } },
{
$set: {
'animals.$[].cats.$[]._id': new ObjectId(),
'animals.$[].dogs.$[]._id': new ObjectId()
}
}
);

But it resulted in the same _id being created for all elements in the “dogs” and “cats” arrays respectively.

Therefore, we will now write JavaScript code to generate unique IDs for each element in the respective nested arrays using forEach loop.

const { MongoClient, ObjectId } = require('mongodb');

const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);

async function generateUniqueIds() {
try {
await client.connect();

const db = client.db('myDatabase');
const collection = db.collection('myCollection');

const pets = await collection.find({ pets: { $ne: [] } }).toArray();

const bulkWriteOperations = [];

pets.forEach(pet => {
pet.pets.forEach(({ cats, dogs }) => {
cats.forEach(cat => {
bulkWriteOperations.push({
updateOne: {
filter: { _id: pet._id, 'pets.cats.name': cat.name },
update: { $set: { 'pets.$[i].cats.$[j]._id': new ObjectId() } },
arrayFilters: [{ 'i.cats.name': cat.name }, { 'j.name': cat.name }]
}
});
});

dogs.forEach(dog => {
bulkWriteOperations.push({
updateOne: {
filter: { _id: pet._id, 'pets.dogs.name': dog.name },
update: { $set: { 'pets.$[i].dogs.$[j]._id': new ObjectId() } },
arrayFilters: [{ 'i.dogs.name': dog.name }, { 'j.name': dog.name }]
}
});
});
});
});

const result = await collection.bulkWrite(bulkWriteOperations);
console.log(`${result.modifiedCount} documents updated`);
} catch (err) {
console.error(err);
} finally {
await client.close();
}
}

generateUniqueIds();

We used MongoDB’s bulk write operation in this scenario to create distinct IDs for every “cat” and “dog” object within the “pets” array of our MongoDB documents.

Within generateUniqueIds(), we utilized the client to connect to our database and retrieve the ‘myCollection’ collection. We used the find() method to retrieve all documents in the collection containing a non-empty “pets” array.

We then set up an empty bulkWriteOperations array to store all of our update operations. We iterated through each document returned by our “pets” query and looped through each animal object in the “pets” array.

For each pet object, we looped through the “cats” and “dogs” arrays and added a updateOne operation to the bulkWriteOperations array for each “cat” and “dog” object.

We then utilized the update property to set the “_id” property of the “cat” or “dog” object to a new ObjectId. We used the arrayFilters property to specify the array element we want to update based on the name of the “cat” or “dog” object.

Finally, we used the bulkWrite method to execute all of our update operations in one batch.

It will return the following output:

{
"_id": ObjectId("6141d4ea6af92531f3e174e1")
"property": "value",
"pets": [
{
"dogs": [
{
"name": "Rufus",
"_id": ObjectId("64480108d38569054192869f"),
},
{
"name": "Buddy",
"_id": ObjectId("64480108d3856905419286a0"),
}
],
"cats": [
{
"name": "Whiskers",
"_id": ObjectId("64480108d38569054192869d"),
},
{
"name": "Fluffy",
"_id": ObjectId("64480108d38569054192869e"),
}
]
}
]
}

In this way, you can add unique identifiers to the nested arrays of data in MongoDB.

I hope you liked the article. 🙌

Linkedin | Twitter

--

--