Sling Academy
Home/Node.js/Mongoose: Perform search with case-insensitive strings

Mongoose: Perform search with case-insensitive strings

Last updated: December 30, 2023

Introduction

Working with databases in JavaScript often involves using Mongoose, an Object Data Modeling (ODM) library for MongoDB. One common requirement in database operations is the ability to perform case-insensitive searches. This is because text data is rarely uniform, and users expect a search to return relevant results regardless of text case. In this tutorial, we will explore how to implement case-insensitive searches using Mongoose in a Node.js application.

Prerequisites

  • Node.js installed on the development machine.
  • Basic understanding of MongoDB and Mongoose.
  • An existing Node.js application with Mongoose installed.

Preparing a Mongoose Model

First, ensure you have a Mongoose model to work with. We’ll start by defining a simple User model with a name attribute which we want to search case-insensitively.

// user.model.js
import mongoose from 'mongoose';

const userSchema = new mongoose.Schema({
  name: String
});

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

export default User;

Basic Case-Insensitive Searches

To perform a basic case-insensitive search, you can use regular expressions with the $regex MongoDB operator applied within a Mongoose query. The i option in the regular expression denotes case insensitivity.

// Basic search using regular expression
import User from './user.model.js';

const searchName = async (name) => {
    const results = await User.find({
        name: { $regex: new RegExp(name, 'i') }
    });
    return results;
};
searchName('john').then(users => {
    console.log(users);
});

However, using regular expressions can be less performant especially with large datasets. An alternative is using Mongoose’s collation() method.

// Search using collation for better performance
const searchNameCollation = async (name) => {
    const results = await User.find({ name }).collation({ locale: 'en', strength: 2 });
    return results;
};

searchNameCollation('john').then(users => {
    console.log(users);
});

Indexing for Case-Insensitive Searches

For optimizing performance, indexing is crucial. We can create indexes to support case-insensitive searches directly in the schema with the use of `collation` and `strength`.

// user.model.js
// ... previous code
userSchema.index({ name: 1 }, { collation: { locale: 'en', strength: 2 } });
// ... remaining code

Advanced Search Capabilities

For more complex scenarios involving full-text search, Mongoose supports text indexes which can be made case-insensitive as well. We will add a text index to the User model and then use the $text and $search options.

// user.model.js
// ... previous code
userSchema.index({ name: 'text' }, { default_language: 'none' });
// ... remaining code

// Full-text search with case insensitivity
const fullTextSearch = async (text) => {
    const results = await User.find({
        $text: {
            $search: text
        }
    }).collation({ locale: 'en', strength: 2 });
    return results;
};

fullTextSearch('John').then(users => {
    console.log(users);
});

Handling Special Characters and Accents

Another aspect of case-insensitive searches is dealing with different forms of the same character, such as accents. MongoDB’s collation feature comes to the rescue once again, and we can define additional parameters to handle such scenarios.

// Search with accent and diacritic insensitivity
const advancedSearch = async (name) => {
    const results = await User.find({ name }).collation({
        locale: 'en',
        strength: 1 // This includes diacritic sensitivity
    });
    return results;
};

advancedSearch('Jöhn').then(users => {
    console.log(users);
});

Conclusion

In this tutorial, we’ve covered a variety of techniques to perform case-insensitive searches in Mongoose. From basic regex queries to utilizing full-text search capabilities and indexing for performance. Understanding these methods allows for the creation of robust, user-friendly querying capabilities in your applications. As database and application requirements grow more complex, mastering these patterns becomes essential for developers.

Remember to use these strategies judiciously, considering the trade-offs in terms of performance and complexity. With careful implementation, case-insensitive searches can significantly enhance the user experience in your projects.

Previous Article: Fixing Mongoose Error: ISODate is not defined in Node.js

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