How to create references between different mongoDB documents.

Photo by Rubaitul Azad on Unsplash

Introduction

When building complex applications with MongoDB and Mongoose, you’ll often find yourself needing to create relationships between different collections. One commonly used technique is referencing documents using MongoDB’s ObjectID. In this article, we’ll explore how to use ObjectID as a reference to other documents in a Mongoose schema and touch upon the use of subdocuments.

ObjectID as a Reference

In MongoDB, each document is automatically assigned a unique identifier known as _id, represented as an ObjectID. You can use this ObjectID to establish relationships between different documents across collections.

Example Schema with ObjectID Reference

Here’s a simple example using Mongoose to demonstrate how to reference another document using ObjectID. Let’s say we have a User model and a Post model, and we want to associate each post with a user.

import mongoose, { Schema, Document } from "mongoose";

// User Schema
interface IUser extends Document {
username: string;
email: string;
}

const UserSchema: Schema = new Schema({
username: { type: String, required: true },
email: { type: String, required: true },
});

const User = mongoose.model<IUser>("User", UserSchema);

// Post Schema with ObjectID reference to User
interface IPost extends Document {
title: string;
content: string;
_user: IUser["_id"];
}

const PostSchema: Schema = new Schema({
title: { type: String, required: true },
content: { type: String, required: true },
_user: { type: Schema.Types.ObjectId, ref: "User" },
});

const Post = mongoose.model<IPost>("Post", PostSchema);

In the PostSchema, notice the _user field. The _user field is set to be of type Schema.Types.ObjectId and references the User model. The underscore _ is a naming convention to indicate that this field is a reference to another document.

Subdocuments

Subdocuments in Mongoose allow you to nest documents within other documents. However, it’s crucial to be mindful of MongoDB’s 16MB size limit for a single document when using nested subdocuments.

Example Schema with Subdocuments

Here, we introduce a recipientSchema and use it as a subdocument in the Post schema.

// Recipient Schema
const recipientSchema: Schema = new Schema({
email: { type: String, required: true },
responded: { type: Boolean, default: false },
});

// Update Post Schema to include recipients field
interface IPost extends Document {
title: string;
content: string;
_user: IUser["_id"];
recipients: typeof recipientSchema[];
}

const PostSchema: Schema = new Schema({
title: { type: String, required: true },
content: { type: String, required: true },
_user: { type: Schema.Types.ObjectId, ref: "User" },
recipients: [recipientSchema],
});

const Post = mongoose.model<IPost>("Post", PostSchema);

In the PostSchema, the recipients field is an array of recipientSchema records. This feature is particularly useful for embedding related data, but it comes with the 4MB size limitation caveat.

When to Use Subdocuments?

Use nested subdocuments sparingly and only when the data in the subdocument has no standalone meaning without the parent document. Otherwise, opt for ObjectID references.

Conclusion

Understanding how to use MongoDB’s ObjectID for referencing documents and the limitations of subdocuments helps in designing a well-structured database schema. The flexibility of MongoDB allows various ways to represent relationships between collections, but being mindful of best practices and limitations ensures that your application is both scalable and maintainable.

,