Sling Academy
Home/Node.js/How to Use Enums in Mongoose: A Practical Guide

How to Use Enums in Mongoose: A Practical Guide

Last updated: December 30, 2023

In the world of NoSQL databases, Mongoose serves as a robust modeling tool for MongoDB, assisting developers in crafting clear schemas with typed data. This guide is tailored to help you adeptly use enumerable fields (enums) within your Mongoose schema definitions.

What are Enums?

Enums, or enumerations, are a feature in many programming languages, including JavaScript and TypeScript, that allow you to define a set of named constants. Using enums ensures that a variable must have one of a limited set of values, which can be especially useful in a database schema context to enforce data integrity.

In Mongoose, enums can be utilized within schema definitions to restrict the values accepted by a particular field. For example, if you have a field that should only accept ‘Yes’, ‘No’, or ‘Maybe’ as valid inputs, you can use an enum to enforce this restriction.

Implementing enums in Mongoose schemas leads to more predictable and secure data by reducing typographical errors and limiting the scope of inputs to the expected set of values.

Setting Up a Basic Enum in Mongoose

We begin by defining a Mongoose schema with a field that should only accept a predefined set of values.

// require the mongoose module
const mongoose = require('mongoose');

// create a new schema using the Schema constructor
const { Schema } = mongoose;

// define the schema
const exampleSchema = new Schema({
  status: {
    type: String,
    enum: ['Open', 'Closed', 'Pending'],
    default: 'Pending'
  }
});

// create a model from the schema
const ExampleModel = mongoose.model('Example', exampleSchema);

This block defines a schema for a collection that contains a status field, which can only be one of ‘Open’, ‘Closed’, or ‘Pending’. The default value for new documents will be ‘Pending’.

When saving a document, Mongoose will validate the status field against the provided enum values.

Advanced Enum Patterns

For more complex scenarios, we might want to further explore enum capabilities within Mongoose. This may involve creating dynamic enums based on other values or integrating with TypeScript for stronger type safety and autocompletion.

In some cases, you might want to define your enums separately or even use numerical values, particularly if you are working with TypeScript. Here’s how you might implement such patterns.

// Defining enums separately
const StatusEnum = Object.freeze({
  OPEN: 'Open',
  CLOSED: 'Closed',
  PENDING: 'Pending'
});

const exampleSchema = new Schema({
  status: {
    type: String,
    enum: Object.values(StatusEnum),
    default: StatusEnum.PENDING
  }
});

// TypeScript example using numerical enums
enum StatusCode {
  Open = 1,
  Closed,
  Pending
}

const exampleSchema = new Schema<{
  status: StatusCode;
}>({ status: {
      type: Number,
      enum: Object.values(StatusCode).filter(value => typeof value === 'number'),
      default: StatusCode.Pending
    }
});

Using separate enum objects or TypeScript enumeration types helps to standardize usage across your codebase, reduce the risk of errors, and improve maintainability.

Error Handling for Enum Validations

When inserting or updating documents in Mongoose, your operations will fail if the data does not comply with the enum definitions. It’s essential to handle these errors gracefully.

The following example demonstrates how to handle such validation errors when saving a document.

const exampleDocument = new ExampleModel({ status: 'InvalidStatus' });
exampleDocument.save().catch(err => {
 if(err.name === 'ValidationError') {
   console.error(`Error: Status must be one of ${Object.values(StatusEnum).join(', ')}.`);
 } else {
   throw err;
 }
});

Here, if an invalid status is provided, Mongoose throws a ValidationError, which we catch and process accordingly.

Integrating Enums with TypeScript

The synergy between Mongoose and TypeScript can be harnessed to provide a stronger type system. Here’s how to use TypeScript Enums with Mongoose.

The first step is to define a TypeScript enum matching the allowed values in the schema.

enum TaskStatus {
  Todo = 'TODO',
  InProgress = 'IN_PROGRESS',
  Done = 'DONE'
}

interface ITask {
  status: TaskStatus;
}

const taskSchema = new mongoose.Schema({ 
  status: { 
    type: String, 
    enum: Object.values(TaskStatus), 
    default: TaskStatus.Todo 
  }
});

const Task = mongoose.model('Task', taskSchema);

With such integration, you gain the ability to utilize TypeScript’s compile-time checks for additional robustness.

Conclusion

The use of enums in Mongoose schemas is vital for ensuring data integrity and providing a clear contract for the data model. It helps reduce bugs and eases communication about valid field values between developers and stakeholders. By understanding these patterns and their implementation using JavaScript or TypeScript, you can rest assured that your Mongoose models are robust and maintain the highest standards in data typing.

Next Article: Using the Mongoose Model.find() function (with examples)

Previous Article: Virtuals in Mongoose: Explained with Examples

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