Sling Academy
Home/Node.js/Exploring Mongoose ObjectId schema type

Exploring Mongoose ObjectId schema type

Last updated: December 30, 2023

Overview

Mongoose is a powerful Object Data Modeling (ODM) library for MongoDB and Node.js that simplifies the process of interacting with MongoDB databases. One of the critical features of Mongoose is the ability to define schemas, which shape the data and enforce structure on the documents in a MongoDB collection. In this tutorial, we’ll explore one fundamental aspect of Mongoose schemas: the ObjectId type. You’ll learn what the ObjectId is, why it’s vital in MongoDB and Mongoose, and how to use it in your Node.js applications with different examples, ranging from the basic setup to more advanced use-cases.

Pre-requisites: A basic understanding of Node.js and MongoDB, as well as a functional MongoDB database and the latest version of Mongoose installed in your Node.js workspace.

Understanding ObjectId

The ObjectId schema type is a 12-byte identifier typically used to uniquely identify documents within a collection. It is also the default type assigned to the _id field of a Mongoose schema. The ObjectId is generated automatically by MongoDB and consists of:

  • A 4-byte value representing the seconds since the Unix epoch
  • A 5-byte random value generated once per process. This ensures that the ID is unique across machines
  • A 3-byte incrementing counter, initialized to a random value

The combination of these values guarantees that every ObjectId is unique across collections, databases, and even distributed systems.

Defining a Mongoose Schema With ObjectId

const mongoose = require('mongoose');
const { Schema } = mongoose;

const userSchema = new Schema({
  name: String
  // _id is added implicitly with type ObjectId
});

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

In the above code snippet, we defined a simple User schema. MongoDB will automatically add an _id field with ObjectId type.

Referencing Other Documents with ObjectId

In more complex schemas, you might need to reference other documents within a collection different from the one you’re defining. In Mongoose, we accomplish this using the ObjectId type in conjunction with the ref option:

const mongoose = require('mongoose');
const { Schema, Types } = mongoose;

const blogPostSchema = new Schema({
  author: { type: Schema.Types.ObjectId, ref: 'User' },
  title: String,
  body: String,
  comments: [{ type: Schema.Types.ObjectId, ref: 'Comment' }]
});

const BlogPost = mongoose.model('BlogPost', blogPostSchema);
const Comment = mongoose.model('Comment', new Schema({ content: String }));

This code snippet demonstrates how to reference documents from two other collections (‘User’ and ‘Comment’) in the BlogPost schema.

Creating and Querying with ObjectId

With your schemas now defined, let’s look into creating new documents complete with ObjectIds and using those Ids to query documents.


// Creating a new User
const createUser = async (name) => {
  const newUser = new User({ name });
  return await newUser.save();
};
 // Creating a new BlogPost with a User reference
const createBlogPost = async (authorId, title, body) => {
  const newBlogPost = new BlogPost({ author: authorId, title, body });
  return await newBlogPost.save();
};

// Querying User by their ObjectId
const findUserById = async (id) => {
  return User.findById(id);
};

// Populate author information in a BlogPost
const getBlogPostWithAuthor = async (id) => {
  return BlogPost.findById(id).populate('author');
};

This example demonstrates the CRUD operations involving ObjectIds, from creating User instances to referencing those in BlogPost documents and fetching the relevant information using the .populate() method.

Updating Documents by ObjectId

Understanding how to efficiently update MongoDB documents using Mongoose and ObjectIds is crucial. Here, we show how to update a user’s name by their unique ObjectId.


const updateUserById = async (userId, newName) => {
  return User.findByIdAndUpdate(userId, { name: newName }, { new: true });
};

The findByIdAndUpdate() is a shortcut for finding a document by its ObjectId and applying an update.

Advanced Operations: Aggregations with ObjectId

Mongoose’s aggregation framework can perform complex transformations and analysis of data. Let’s consider an example where we use ObjectId in aggregation pipelines to fetch post counts:


const getUserPostCount = async (userId) => {
  return BlogPost.aggregate([
    { $match: { author: mongoose.Types.ObjectId(userId) } },
    { $group: { _id: '$author', postCount: { $sum: 1 } } }
  ]);
};

This piece of code will count all BlogPosts for a given user, demonstrating the handling of ObjectId within an aggregation framework. Notice how we use mongoose.Types.ObjectId to cast the userId to an ObjectId explicitly.

Conclusion

We’ve covered the essentials and advanced usage of ObjectId within Mongoose, from defining schemas to performing amendments and aggregations with this native MongoDB type. Understanding ObjectId is crucial, as it allows robust referencing and structuring within documents, granting seamless interaction with the MongoDB database within a Node.js context.

Embrace these concepts and examples, experiment with ObjectIds in your schemas, and leverage the power of Mongoose to build efficient, robust, and scalable applications. Transcend the basics and venture into more intricate operations sets you on the path to mastering MongoDB with the help of Mongoose.

Next Article: Using Array schema type in Mongoose

Previous Article: Mongoose: How to define MongoDB indexes

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