Sling Academy
Home/Node.js/How to create multifield indices in Mongoose

How to create multifield indices in Mongoose

Last updated: December 30, 2023

Introduction

Mongoose is a powerful Object Data Modeling (ODM) library for MongoDB and Node.js. It manages relationships between data, provides schema validation, and translates between objects in code and their representation in MongoDB. Indexing is a key feature to improve the performance of database operations, particularly search queries, which can be optimized using multifield (compound) indices. In MongoDB, an index can span more than one field, allowing for efficient queries that touch upon multiple data aspects. In this guide, you will learn how to create and manage multifield indices in Mongoose using modern JS/TS syntax.

Prerequisites

  • Basic understanding of Node.js and Mongoose.
  • A MongoDB database instance.
  • An existing Node.js application with Mongoose installed.

Creating a Simple Multifield Index

Let’s start by defining a schema:

import mongoose from 'mongoose';
const { Schema } = mongoose;

const userSchema = new Schema({
    username: String,
    email: String,
    createdAt: { type: Date, default: Date.now }
});

// Create multifield index
userSchema.index({username: 1, createdAt: -1});

export const User = mongoose.model('User', userSchema);

Explanation:

  • The index() method adds a compound index to the fields username and createdAt.
  • The value 1 specifies an ascending index and -1 specifies a descending index.

Using Index Options

Mongoose also supports index options:

userSchema.index({ username: 1, email: 1 }, { unique: true });

This compound index enforces that each combination of username and email must be unique.

Invalidating Duplicates Across Multiple Fields

To automatically handle errors use asynchronous error trapping around your save operations:

const createUser = async (userData) => {
    try {
        const user = new User(userData);
        await user.save();
    } catch (error) {
        console.error('Error creating user:', error);
        // Handle the error appropriately
    }
};

Advanced Usage: Complex Multifield Index Conditions

More sophisticated indices can use conditions:

userSchema.index({ username: 1, 'profile.status': 1 }, { partialFilterExpression: { 'profile.status': { $exists: true } } });

This only creates an index on documents where the profile.status exists.

Index Administration

To ensure that indices are being created during start-up use:

mongoose.connection.on('open', function () {
    User.init().then(() => console.log('Indices are built or confirmed.'));
});

Benchmarking Queries

You should benchmark indexed queries to understand performance gains:

User.find({ username: 'john_doe', createdAt: { $gte: new Date('2021-01-01') } })
    .explain('executionStats')
    .then(stats => console.log(stats));

Comparing the execution stats, look for the reduction in the ‘totalKeysExamined’ and ‘totalDocsExamined’ numbers to measure the effectiveness of your index.

Conclusion

Understanding how to implement multifield indexing in Mongoose effectively elevates the performance of your applications making use of MongoDB. In the advanced realm of NoSQL databases, properly indexing is crucial to reaping the benefits of its schema-less nature without incurring performance degradation. We have learned the foundational knowledge of creating and administering multifield indices, while considering best practices such as index uniqueness, conditioned indices, and regularly monitoring query performances.

Next Article: Mongoose Data Validation Examples

Previous Article: Mongoose: How to filter documents by multiple fields

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