Sling Academy
Home/MongoDB/MongoDB: How to add UNIQUE constraint to a field (with examples)

MongoDB: How to add UNIQUE constraint to a field (with examples)

Last updated: February 02, 2024

Introduction

MongoDB is a flexible NoSQL database that allows developers to store semi-structured data. By default, MongoDB does not impose constraints on the uniqueness of fields, except for the _id field, which is automatically unique. However, there are cases when you may want to ensure that a field or a combination of fields is unique across documents in a collection.

Understanding Uniquest Constraints in MongoDB

In MongoDB, a unique constraint can be applied to a field using an index. Creating a unique index on a field will prevent the insertion or updating of a document if it results in a duplicate value for that index. The unique index guarantees that the indexed fields do not store duplicate values.

Creating a Unique Index

db.collection.createIndex({"email": 1}, {unique: true});

The above command creates a unique index on the email field in the collection. This will prevent two documents from having the same email.

Adding a Unique Constraint to an Existing Collection

If you already have a collection and you want to add a unique constraint to one of its fields, you can still create a unique index. However, it’s essential to make sure that there are no duplicate values for the field you are indexing, as indexing will fail if duplicates are found.

For instance, to add a unique constraint to the username field:

db.users.createIndex({"username": 1}, {unique: true});

Before running this command, you would want to remove or modify any duplicate usernames.

Handling Duplicates Before Creating a Unique Index

You can find and remove duplicates using a script or aggregation pipeline, depending on the complexity of your duplicates. A basic example to find duplicates for the username field could be:

db.users.aggregate([
    { $group: {
        _id: { username: "$username" },
        uniqueIds: { $addToSet: "$_id" },
        count: { $sum: 1 }
    }},
    { $match: {
        count: { $gt: 1 }
    }}
]).forEach(function(doc) {
    doc.uniqueIds.pop(); // Keep one document
    db.users.remove({ _id: { $in: doc.uniqueIds }});
});

This aggregation pipeline groups the documents by the username field, then filters the groups to only those with more than one document. Then, for each group, it keeps one document and removes the others.

Working with Compound Unique Indexes

There are situations where a unique constraint should be based on a combination of fields. MongoDB allows for the creation of compound indexes that are unique.

db.orders.createIndex(
  { "customerId": 1, "orderId": 1 },
  { unique: true }
);

This command creates a unique index on a compound key that includes both the customerId and orderId fields, enforcing unique combinations of these fields across documents.

Error Handling When Violating Unique Constraints

When an operation violates a unique constraint, MongoDB will raise a duplicate key error. It’s important to handle these errors in your application code, typically by providing a user-friendly message, logging the error, and/or retrying the operation with different values.

Dealing with Unique Indexes in Sharded Collections

Creating unique indexes on sharded collections has special considerations. The unique index key must be either the shard key itself or contain it as a prefix. Without satisfying this requirement, you cannot create a unique index on a sharded collection.

db.shardedCollection.createIndex(
  { "shardKey": 1, "uniqueField": 1 },
  { unique: true }
);

This is an example of creating a unique index on a sharded collection that includes the shard key and another field.

Advanced Scenarios: Partial and Sparse Unique Indexes

There are cases when unique constraints should apply only to documents meeting certain criteria. MongoDB’s partial indexes can enforce uniqueness only for documents that match a specified filter expression.

db.products.createIndex(
    {"productCode": 1},
    {
        unique: true,
        partialFilterExpression: {
            quantity: { $gt: 0 }
        }
    }
);

This index enforces uniqueness for the productCode field, but only for documents where the quantity is greater than 0.

Sparse Indexes

Sparse indexes only index documents that have the indexed field. It’s a way to enforce uniqueness on fields that may not always be present.

db.customers.createIndex(
  { "discountCode": 1 },
  { unique: true, sparse: true }
);

This creates a unique sparse index on the discountCode field, which will enforce uniqueness on documents where discountCode exists.

Synergizing with Application Logic

Beyond database constraints, ensuring uniqueness often involves application-level checks in your code. Before inserting or updating data, querying for the existence of a value may be prudent to provide a better user experience.

if (db.collection.findOne({email: newUserEmail})) {
    // handle error due to email already existing
} else {
    // proceed with inserting a new document
}

This check helps to mitigate race conditions that can still occur when relying solely on database uniqueness constraints, especially in heavy load scenarios.

Conclusion

In summary, MongoDB provides various methods to enforce unique constraints through unique indexes, compound unique indexes, and partial or sparse indexes. These constraints are essential tools for maintaining data integrity and preventing duplicates, contributing to the overall stability and reliability of applications using MongoDB.

Next Article: MongoDB db.collection.findAndModify() method (with examples)

Previous Article: MongoDB: Is there something like ‘NOT NULL’ constraint in SQL?

Series: MongoDB Tutorials

MongoDB

You May Also Like

  • MongoDB: How to combine data from 2 collections into one
  • Hashed Indexes in MongoDB: A Practical Guide
  • Partitioning and Sharding in MongoDB: A Practical Guide (with Examples)
  • Geospatial Indexes in MongoDB: How to Speed Up Geospatial Queries
  • Understanding Partial Indexes in MongoDB
  • Exploring Sparse Indexes in MongoDB (with Examples)
  • Using Wildcard Indexes in MongoDB: An In-Depth Guide
  • Matching binary values in MongoDB: A practical guide (with examples)
  • Understanding $slice operator in MongoDB (with examples)
  • Caching in MongoDB: A practical guide (with examples)
  • CannotReuseObject Error: Attempted illegal reuse of a Mongo object in the same process space
  • How to perform cascade deletion in MongoDB (with examples)
  • MongoDB: Using $not and $nor operators to negate a query
  • MongoDB: Find SUM/MIN/MAX/AVG of each group in a collection
  • References (Manual Linking) in MongoDB: A Developer’s Guide (with Examples)
  • MongoDB: How to see all fields in a collection (with examples)
  • Type checking in MongoDB: A practical guide (with examples)
  • How to query an array of subdocuments in MongoDB (with examples)
  • MongoDB: How to compare 2 documents (with examples)