Sling Academy
Home/Node.js/How to set unique index in Mongoose (with examples)

How to set unique index in Mongoose (with examples)

Last updated: December 30, 2023

Introduction

Mongoose is a MongoDB object modeling tool designed to work in an asynchronous environment like Node.js. Defining indexes at the schema level is an essential feature in Mongoose, which can increase query performance and enforce data uniqueness. In this guide, we’ll explore how to set unique indexes in Mongoose schemas, with practical examples ranging from basic to advanced use cases, using the latest ES6/ESNext syntax recommended for JavaScript and TypeScript development.

Indexes serve as “pointers” to the documents in a database. A unique index ensures that the value corresponding to the indexed field is never duplicated across documents in the collection. This facilitates very fast searches and is valuable for both performance optimization and data integrity. Throughout this tutorial, we’ll be covering how to create these unique indexes using Mongoose’s schema API.

Note: This guide assumes that you have a fundamental understanding of Node.js, npm, and basic Mongoose operations.

Setting Up a Simple Unique Index

To get started, first ensure you have Mongoose installed:

npm install mongoose

Once installed, connect to your MongoDB instance:

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:yourPort/yourDB', {
  useNewUrlParser: true,
  useUnifiedTopology: true
});

Now you’re ready to define a simple schema with a unique index:

const UserSchema = new mongoose.Schema({
  username: {
    type: String,
    unique: true
  }
});
const User = mongoose.model('User', UserSchema);

The unique: true flag in the schema definition tells Mongoose to create a unique index on the username field. This implies that any attempt to insert a user with a duplicate username will result in an error.

Handling Unique Index Errors

Let’s see how to handle uniqueness errors during insertion:

const createUniqueUser = async (username) => {
  try {
    const newUser = new User({ username });
    await newUser.save();
    console.log('User created successfully');
  } catch (error) {
    if (error.code === 11000) {
      console.error('Username must be unique');
    } else {
      console.error(error);
    }
  }
};

createUniqueUser('john_doe');

We’re performing an async insertion using await, wrapped in a try-catch block—If there’s a duplicate key error (error code 11000), we handle it by logging an appropriate message.

Advanced Unique Indexing

For more complex scenarios, like compound indexes, Mongoose offers more nuanced control over indexing strategy:

const UserDataSchema = new mongoose.Schema({
  email: {
    type: String,
    unique: true
  },
  accountId: {
    type: Number,
    unique: true
  }
});

UserDataSchema.index({ email: 1, accountId: 1 }, { unique: true });

The compound index creation shown above will enforce uniqueness across the combination of email and accountId fields, which ensures a high-performance query on both fields when they’re used together, in addition to maintaining unique pairs of values.

Using Unique Index with Additional Options

Mongoose also allows you to pass additional options when defining unique indexes. For example, you can provide a custom error message that’s more revealing and helpful than the default MongoDB error messages:

const AccountSchema = new mongoose.Schema({
  accountNumber: {
    type: String,
    unique: true,
    uniqueCaseInsensitive: true
  }
});

AccountSchema.path('accountNumber').index({ unique: true, uniqueCaseInsensitive: true },
  'Duplicate account number');

Here, the uniqueCaseInsensitive: true option in AccountSchema.path().index() specifies that Mongoose should apply a unique index on the accountNumber field in a case-insensitive manner. The error message to be returned when uniqueness is violated is also specified.

Conclusion

To wrap up, we have discussed the importance of unique indexes in both optimizing query performance and ensuring data integrity when using Mongoose with MongoDB. Starting with the basics of setting up unique indexes, handling errors, and moving on to more advanced use cases like compound and case-insensitive unique indexes, you should now have the knowledge to implement these indexing strategies within your own Mongoose models.

Remember to test thoroughly any unique index constraints you put in place, as they form a critical part of ensuring the validity of your data. Also, consider the performance implications of these indexes, and use them appropriately within a context that benefits from their strengths.

Unique indexes are a powerful feature of both MongoDB and Mongoose, and getting familiar with how to use them effectively is going to significantly bolster the capabilities of any application dealing with unique datasets.

Next Article: Fix mongoError: Topology was destroyed – Mongoose

Previous Article: Mongoose: How to push object to an array in a document

Series: Mongoose.js Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates