Share
Explore

🛠️ Lab Notebook: Joining Two MongoDB Collections Using Mongoose


🔍 Objective

In this lab, students will learn how to join two collections in MongoDB using Mongoose. The focus will be on referencing documents between collections and retrieving related data efficiently.
We will use an interesting real-world scenario: 📚 Library System → Tracking books and their authors using two collections:
authors → Contains information about authors.
books → Contains books written by authors (linked via authorId).
Students will: ✅ Create two collections (authors & books)Establish relationships between themPerform queries to retrieve joined data

📌 Step 1: Setup the Project

1️⃣ Initialize a Node.js Project

mkdir mongo-joins-lab
cd mongo-joins-lab
npm init -y

2️⃣ Install Dependencies

npm install mongoose dotenv

mongoose → Handles MongoDB interactions ✅ dotenv → Stores MongoDB connection URL

3️⃣ Create Required Files

touch app.js .env models/Author.js models/Book.js

📌 Step 2: Define MongoDB Collections (Mongoose Models)

📄 models/Author.js (Author Collection)

This collection stores author information.
const mongoose = require("mongoose");

const AuthorSchema = new mongoose.Schema({
name: { type: String, required: true },
age: Number,
nationality: String
});

module.exports = mongoose.model("Author", AuthorSchema);

✅ Each author has a name, age, and nationality.

📄 models/Book.js (Book Collection)

This collection references an author using authorId.
const mongoose = require("mongoose");

const BookSchema = new mongoose.Schema({
title: { type: String, required: true },
genre: String,
author: { type: mongoose.Schema.Types.ObjectId, ref: "Author" } // Reference to Author
});

module.exports = mongoose.model("Book", BookSchema);

✅ Each book has a title, genre, and a reference (authorId) to an Author.

📌 Step 3: Connect to MongoDB & Seed Data

📄 .env (Database Configuration)

MONGO_URI=your_mongodb_atlas_connection_string

👉 Replace your_mongodb_atlas_connection_string with your MongoDB Atlas connection string.

📄 app.js (Main Logic)

Paste this code to: ✅ Connect to MongoDBInsert sample authors & booksQuery books with their author details
require("dotenv").config();
const mongoose = require("mongoose");
const Author = require("./models/Author");
const Book = require("./models/Book");

mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log("✅ MongoDB Connected"))
.catch(err => console.log("❌ Connection Error:", err));

// 🌱 Seed Sample Data
const seedDatabase = async () => {
try {
await Author.deleteMany({});
await Book.deleteMany({});

const author1 = await new Author({ name: "J.K. Rowling", age: 57, nationality: "British" }).save();
const author2 = await new Author({ name: "George R.R. Martin", age: 74, nationality: "American" }).save();

await new Book({ title: "Harry Potter", genre: "Fantasy", author: author1._id }).save();
await new Book({ title: "Game of Thrones", genre: "Fantasy", author: author2._id }).save();
await new Book({ title: "A Clash of Kings", genre: "Fantasy", author: author2._id }).save();

console.log("✅ Database Seeded");
} catch (err) {
console.error("❌ Seeding Error:", err);
}
};

// 📚 Query Books with Author Data
const fetchBooksWithAuthors = async () => {
try {
const books = await Book.find().populate("author", "name nationality"); // Fetch author details

console.log("📖 Books with Authors:");
console.log(books);
} catch (err) {
console.error("❌ Query Error:", err);
} finally {
mongoose.connection.close();
}
};

// Run the Functions
(async () => {
await seedDatabase();
await fetchBooksWithAuthors();
})();

📌 Step 4: Run the Application

node app.js

✅ This will: 🔹 Connect to MongoDB 🔹 Insert authors & books 🔹 Query books & join author details

📌 Step 5: Understanding the JOIN (Populate)

❓ How does MongoDB join the collections?

In this query:
const books = await Book.find().populate("author", "name nationality");

1️⃣ Book.find() → Fetches all books 2️⃣ .populate("author", "name nationality")Joins the books collection with authors, retrieving only the name and nationality fields.

📌 Step 6: Expected Output

After running node app.js, the output should be:
📖 Books with Authors:
[
{
"_id": "65a1d80f83f8ab12df93b012",
"title": "Harry Potter",
"genre": "Fantasy",
"author": {
"_id": "65a1d80f83f8ab12df93a987",
"name": "J.K. Rowling",
"nationality": "British"
}
},
{
"_id": "65a1d80f83f8ab12df93b013",
"title": "Game of Thrones",
"genre": "Fantasy",
"author": {
"_id": "65a1d80f83f8ab12df93a988",
"name": "George R.R. Martin",
"nationality": "American"
}
},
{
"_id": "65a1d80f83f8ab12df93b014",
"title": "A Clash of Kings",
"genre": "Fantasy",
"author": {
"_id": "65a1d80f83f8ab12df93a988",
"name": "George R.R. Martin",
"nationality": "American"
}
}
]

🎉 Each book now includes its author's details!

📌 Step 7: Summary

Created two collections: authors and booksEstablished relationships (Each book has an authorId) ✅ Used .populate() to join collections dynamicallyRetrieved books with author details in a single query

📌 Step 8: Further Enhancements

📌 Want to practice more? Try these:
🛠 Add more fields (e.g., publishedYear, awards)
📚 Query authors and list all books they wrote
🚀 Build an Express.js API to retrieve joined data
🎯 Final Thought:Joins in MongoDB using Mongoose's .populate() are powerful and efficient. This lab provides a hands-on approach to mastering relationships in NoSQL databases.
🚀 Now, go ahead and experiment! 🚀
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.