Skip to main content

Is the _id Property in MongoDB 100% Unique?

 MongoDB is a NoSQL database that operates with collections and documents. Each document created on MongoDB has a unique object ID property. So when creating a document without entering an ID, the document will be created with an auto-generated ID.

Who Generates the ID?

When filling in the properties of a document, we do not necessarily need to enter the object ID. But when we refer to MongoDB after creating a document, it would have an object ID that looks like this:

{ 
“_id”: “5f1819229fdf8a0c7c2d8c36”
}

This makes it much easier for us when creating documents in MongoDB and saves us a lot of time. The object ID in the documents in MongoDB is created by the MongoDB driver, which talks to MongoDB. Therefore, this brings out a lot of advantages:

  • You do not need to wait for MongoDB to create a new unique identifier.
  • Applications of MongoDB are highly scalable.
  • You can create several instances of MongoDB.
  • There is no need to talk to a central place to get a unique identifier.

Properties of the Object ID

An object ID is 24 characters long with two characters taking up to one byte, thus containing a total of 12 bytes. Here is what the 12 bytes of the object ID tell us.

Timestamp

The first four bytes of the object ID represent the timestamp when the document was created. We avoid the need to create a separate property in the document such as created-at and can thus save time and have optimized lines of code.

Due to the contribution of the timestamp to the object ID, we can obtain the time when the document was created by referring to the ID exclusively. Therefore, when querying the data, we do not need a different method to sort the documents by the timestamp.

You can obtain the timestamp of an object by using the following commands:

const mongoose = require('mongoose');// Create object Id on memory
const id = new mongoose.Types.ObjectId();
// Get timestamp
console.log(id.getTimestamp());

Machine identifier

The next three bytes represent the machine identifier (i.e. the machine that the document was created on). Suppose two documents were created at the same time on different machines. These three bytes would be different, adding to the uniqueness of the object ID.

Process identifier

The next two bytes represent the process identifier (i.e. the process in the machine that the document was created on). Suppose two documents were created at the same time on the same machine, but with different processes. These two bytes will be different, adding to the uniqueness of the object ID.

Counter

The last three bytes represent a counter. This counter is an auto-incrementing number similar to other counter variables in SQL and NoSQL databases that makes the object ID unique (in SQL, this may hinder scalability). Suppose two documents were created at the same time on the same machine and on the same process. The counter bytes will be different, contributing to the uniqueness of the object ID.

The Object ID Problem

In MongoDB, a problem arises with the counter in the object ID that may limit its uniqueness.

The object ID is only unique as long as the counter does not overflow!

The counter overflow problem is when the counter has reached its maximum capacity, leading to documents having the same object ID. Therefore, the object ID is almost unique but not 100% unique!

Here is why: The counter is being allocated three bytes. This means it has the capacity to represent up to 16 million numbers. If that many documents are generated at the same time, on the same machine, and the same process, two documents can share the same object ID.

Using Mongoose

When building applications using Node.js and Express.js, we use mongoose. Mongoose is an abstraction over the MongoDB driver. Therefore, when creating a document, mongoose talks to the MongoDB driver to create a new object ID.

Creating an object ID

// create an object id on memory - Not on DB!const mongoose = require('mongoose');const id = mongoose.Types.ObjectId();
console.log(id);
// output -> 5f1819229fdf8a0c7c2d8c36

Validating object ID

With mongoose, you can also validate the object ID statically using the isValid property:


const mongoose = require('mongoose');
// create object Id
const id = new mongoose.Types.ObjectId();
// validate object Id
const isValid = mongoose.Types.ObjectId.isValid(id);
console.log(isValid);
// Output -> true


Conclusion

The MongoDB object ID is unique unless a certain scenario (discussed above) is reached. Therefore, as software developers, we should consider the size and complexity of the system for a trade-off between the auto-generated ID and a custom object ID.

The approach is entirely up to you to decide. For more information regarding the MongoDB Object ID, you can refer to the official documentation of MongoDB and Mongoose.

I hope this story has educated you on the uniqueness and reliability of the Object ID in MongoDB. Have fun learning and enjoy coding!




















Comments

Popular posts from this blog

How to use Ngx-Charts in Angular ?

Charts helps us to visualize large amount of data in an easy to understand and interactive way. This helps businesses to grow more by taking important decisions from the data. For example, e-commerce can have charts or reports for product sales, with various categories like product type, year, etc. In angular, we have various charting libraries to create charts.  Ngx-charts  is one of them. Check out the list of  best angular chart libraries .  In this article, we will see data visualization with ngx-charts and how to use ngx-charts in angular application ? We will see, How to install ngx-charts in angular ? Create a vertical bar chart Create a pie chart, advanced pie chart and pie chart grid Introduction ngx-charts  is an open-source and declarative charting framework for angular2+. It is maintained by  Swimlane . It is using Angular to render and animate the SVG elements with all of its binding and speed goodness and uses d3 for the excellent math functions, scales, axis and shape ge

JavaScript new features in ES2019(ES10)

The 2019 edition of the ECMAScript specification has many new features. Among them, I will summarize the ones that seem most useful to me. First, you can run these examples in  node.js ≥12 . To Install Node.js 12 on Ubuntu-Debian-Mint you can do the following: $sudo apt update $sudo apt -y upgrade $sudo apt update $sudo apt -y install curl dirmngr apt-transport-https lsb-release ca-certificates $curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - $sudo apt -y install nodejs Or, in  Chrome Version ≥72,  you can try those features in the developer console(Alt +j). Array.prototype.flat && Array.prototype. flatMap The  flat()  method creates a new array with all sub-array elements concatenated into it recursively up to the specified depth. let array1 = ['a','b', [1, 2, 3]]; let array2 = array1.flat(); //['a', 'b', 1, 2, 3] We should also note that the method excludes gaps or empty elements in the array: let array1

Understand Angular’s forRoot and forChild

  forRoot   /   forChild   is a pattern for singleton services that most of us know from routing. Routing is actually the main use case for it and as it is not commonly used outside of it, I wouldn’t be surprised if most Angular developers haven’t given it a second thought. However, as the official Angular documentation puts it: “Understanding how  forRoot()  works to make sure a service is a singleton will inform your development at a deeper level.” So let’s go. Providers & Injectors Angular comes with a dependency injection (DI) mechanism. When a component depends on a service, you don’t manually create an instance of the service. You  inject  the service and the dependency injection system takes care of providing an instance. import { Component, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ selector: 'app-test', templateUrl: './test.component.html', styleUrls: ['./test.component