Sling Academy
Home/Node.js/How to auto-generate timestamps in Mongoose

How to auto-generate timestamps in Mongoose

Last updated: December 30, 2023

Overview

Automatically generating timestamps is a common requirement in application development, capable of providing valuable insights into when a document was created or last modified within a database. Mongoose, a MongoDB object modeling tool designed for asynchronous environments such as Node.js, streamlines the process of working with MongoDB and includes functionality for this very purpose. This tutorial will cover how to auto-generate timestamps in Mongoose using the latest JavaScript and Node.js syntax.

Setting Up

Before we delve into timestamps, make sure you have Node.js and MongoDB installed on your system. Begin by initializing a new Node.js project with:

npm init -y

Then install Mongoose:

npm install mongoose

Basic Mongoose Schema with Timestamps

The most basic use case involving timestamps is to ‘auto-generate’ them within a Mongoose schema; Every new instance will have ‘createdAt’ and ‘updatedAt’ fields automatically. Here’s how:

import mongoose from 'mongoose';

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

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

Now, whenever you create a new User document, Mongoose will add createdAt and updatedAt fields containing timestamps of creation and last modification times, respectively.

Customizing Timestamps

If you’d like to customize the names of your timestamp fields, you can do so easily:

const customUserSchema = new mongoose.Schema({
  username: String
}, {
  timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }
});

const CustomUser = mongoose.model('CustomUser', customUserSchema);

Advanced Usage: Middleware and Manual Timestamps

Sometimes, automated timestamps aren’t flexible enough, and you may need to manipulate them manually using Mongoose middlewares, also known as hooks:

userSchema.pre('save', function(next) {
  if (this.isNew) {
    this.created_at = new Date();
  } else if (this.isModified()) {
    this.updated_at = new Date();
  }
  next();
});

This code uses the pre hook to manually set created_at and updated_at before saving the document to the database.

Using Virtuals for Derived Timestamps

Mongoose virtuals allow you to define fields that Mongoose does not persist to MongoDB. These are useful for derived properties. Consider the following example, where we create a ‘timeSinceCreation’ virtual:

userSchema.virtual('timeSinceCreation').get(function() {
  return Date.now() - this.created_at.getTime();
});

You can then access the ‘timeSinceCreation’ property, which will calculate the time elapsed since the user was created.

Handling Timestamps with Nested Schemas

Moving towards a more advanced scenario, consider handling documents that contain subdocuments. Each subdocument can also have its own timestamps, like so:

const postSchema = new mongoose.Schema({
  title: String,
  content: String,
  comments: [{
    text: String,
    timestamps: true
  }]
}, {
  timestamps: true
});

Here, both your posts and individual comments inside posts will have their own pairs of timestamps.

Error Handling with Async/Await and Timestamps

Mongoose operations often necessitate excellent error handling, especially when dealing with asynchronous code. Let’s use async/await:

const createUser = async (userData) => {
  try {
    const user = await User.create(userData);
    console.log('User created with timestamps:', user);
  } catch (error) {
    console.error('Error creating user:', error);
  }
};

The above function responsibly creates a user and logs their timestamps, while also catching any errors that might occur during the process.

Conclusion

To auto-generate timestamps in Mongoose effectively, opting for the inbuilt Mongoose timestamps option is usually the best starting point. Conveniently defining, customizing, or even manipulating timestamps through middleware offers a flexible solution capable of satisfying most needs. With these capabilities and the powerful asynchronous support Node.js offers, Mongoose handles the temporal dimensions of your application data with assurance and elegance, clearing your path to focus on delivering the best user experience possible.

Next Article: How to Auto-Hash Passwords in Mongoose

Previous Article: How to Validate Email Addresses in Mongoose

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