Sling Academy
Home/Node.js/Mongoose: Auto add createdAt and updatedAt timestamps

Mongoose: Auto add createdAt and updatedAt timestamps

Last updated: December 30, 2023

Introduction

Mongoose is a powerful Object Data Modeling (ODM) library for MongoDB and Node.js that manages relationships between data, provides schema validation, and translates between objects in code and their representation in MongoDB. One common requirement in applications is keeping track of when a document was created and last updated. This tutorial demonstrates how to automatically add createdAt and updatedAt timestamps to your Mongoose schemas using built-in schema options and custom middleware.

Enabling Timestamps in Schema

Mongoose provides an easy way to enable automatic management of createdAt and updatedAt fields in your schemas via the timestamps schema option. Here’s how you can do it:

import mongoose from 'mongoose';

const userSchema = new mongoose.Schema({
  username: String,
  email: String
}, {
  timestamps: true
});

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

With the above schema, Mongoose will automatically add createdAt and updatedAt fields to the User documents upon creation and update these fields respectively whenever the documents are modified.

Customizing Field Names

If you want to customize the names of the timestamp fields, you can set the timestamps option to an object specifying the field names:

const userSchema = new mongoose.Schema({
  // fields
}, {
  timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }
});

This will result in timestamp fields named created_at and updated_at instead.

Advanced Timestamps Customization

If the default behavior of the timestamp does not fit your needs, or you need to add more complex logic to the setting of these fields, you can use Mongoose middleware (pre and post hooks).

userSchema.pre('save', function (next) {
  const now = new Date();
  this.updatedAt = now;
  if (!this.createdAt) {
    this.createdAt = now;
  }
  next();
});

userSchema.pre('updateOne', function (next) {
  this.set({ updatedAt: new Date() });
  next();
});

userSchema.pre('findOneAndUpdate', function (next) {
  this.set({ updatedAt: new Date() });
  next();
});

With these middleware functions, specifically, the pre-save hook checks if the createdAt field has not been set before and updates the updatedAt field, whereas the pre-updateOne and pre-findOneAndUpdate hooks ensure that the updatedAt field is updated on each respective operation.

Dealing with Nested Schemas

Oftentimes, your mongoose documents will contain nested schemas. To ensure timestamps are correctly managed in those as well, you can enable timestamps in the nested schemas separately:

const reviewSchema = new mongoose.Schema({
  content: String
}, {
  timestamps: true
});

const productSchema = new mongoose.Schema({
  name: String,
  reviews: [reviewSchema]
}, {
  timestamps: true
});

This will add createdAt and updatedAt fields both to the Product documents and each review subdocument.

Error Handling

While enabling and customizing timestamps is often straightforward, developers should also handle possible errors gracefully. For instance, always check for possible errors during database operations.

const saveUser = async (userData) => {
  const newUser = new User(userData);
  try {
    await newUser.save();
    return newUser;
  } catch (error) {
    console.error('Error saving user:', error);
    throw error;
  }
};

Indexing Timestamps

Another advanced topic is indexing your timestamp fields for performance enhancements, especially if you often query documents based on creation or modification dates.

userSchema.index({ createdAt: 1 });
userSchema.index({ updatedAt: 1 });

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

These indexes will speed up sorting and querying operations based on the timestamp fields.

Summary

In this tutorial, we’ve covered how to effortlessly integrate automatic timestamps in Mongoose schemas for Node.js applications. We’ve looked at how to apply decent naming conventions and enable advanced customization options, setup of nested schemas timestamps, the importance of error handling, and indexing timestamp fields for performance optimization. Tracking document creation and update times is crucial for many applications, and Mongoose makes this process seamless. With these techniques, you’re well-equipped to handle timestamps in your next Node.js project backed by Mongoose and MongoDB.

Next Article: Mongoose: Remove password field from query results

Previous Article: Fixing Mongoose Unhandled Rejection Error: URL Malformed

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