Open In App

How to Create Relationships with Mongoose and Node.JS?

Last Updated : 09 Jun, 2025
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

Mongoose is a powerful ODM (Object Data Modeling) library for MongoDB and Node.js, allowing developers to define schemas and interact with MongoDB using models. Creating relationships between schemas is important for building complex applications with interrelated data. This article will guide you through setting up and managing relationships with Mongoose in a Node.js application.

Why Are Relationships Important in MongoDB?

Unlike traditional SQL databases, MongoDB is a NoSQL document-oriented database, which stores data in flexible, JSON-like documents. While MongoDB does not enforce relationships like relational databases, Mongoose provides ways to model relationships, helping you keep your data consistent and easy to query.

Two common types of relationships in MongoDB using Mongoose:

  • Referencing (Normalization): Storing ObjectId references from one document to another (like foreign keys).
  • Embedding (Denormalization): Nesting related documents directly within a parent document.

Steps on How to Create Relationships with Mongoose and Node.JS

Step 1: Create a New Directory

At first create a new directory for your project and navigate into it.

mkdir Your_folder_name
cd Your_folder_name

Step 2: Initialize a New Node.js Project

After that, you have to Initialize a new node project using npm.

npm init -y

Step 3: Install required packages

Then install the the required package using npm.

npm install express mongoose ejs body-parser

Step 4: Project Structure

Screenshot-_536_
Folder structure

Dependencies

"dependencies": {
"body-parser": "^1.20.2",
"ejs": "^3.1.10",
"express": "^4.19.2",
"mongoose": "^8.5.1"
}
}

Step 5: Define Your Mongoose Schemas with Relationships

Let’s say we want to create a simple app with Authors and Books, where each book references an author.

HTML
<!-- views/layout.ejs code... -->

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mongoose Relations</title>
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap">
    <link rel="stylesheet" href="/style.css">
</head>

<body>
    <header>
        <h1>Mongoose Relations</h1>
        <nav>
            <ul>
                <li class="nav-lists"><a href="/authors">Authors</a></li>
                <li class="nav-lists"><a href="/books">Books</a></li>
            </ul>
        </nav>
    </header>
</body>

</html>
HTML
<!-- views/books.ejs code... -->

<%- include('layout') %>

    <h2 class="books-heading">Books</h2>
    <form action="/books" method="POST">
        <label for="title">Title</label>
        <input type="text" name="title" id="title" required>

        <label for="author">Author</label>
        <select name="author" id="author" required>
            <% authors.forEach(author=> { %>
                <option value="<%= author._id %>">
                    <%= author.name %>
                </option>
                <% }) %>
        </select>

        <button type="submit">Add Book</button>
    </form>

    <ul class="books-lists">
        <% books.forEach(book=> { %>
            <li>
                <%= book.title %> by <%= book.author.name %>
            </li>
            <% }) %>
    </ul>
HTML
<!-- views/authors.ejs code... -->

<%- include('layout') %>

    <h2 class="author-heading">Authors</h2>
    <form action="/authors" method="POST">
        <label for="name">Name</label>
        <input type="text" name="name" id="name" required>
        <button type="submit">Add Author</button>
    </form>

    <ul class="author-lists">
        <% authors.forEach(author=> { %>
            <li>
                <%= author.name %>
            </li>
            <% }) %>
    </ul>
CSS
/* public/style.css code.... */
body,
h1,
h2,
p,
ul {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Roboto', sans-serif;
    background-color: #f4f7f6;
    color: #333;
    line-height: 1.6;
}

header {
    background-color: rgb(29, 231, 29);
    color: white;
    padding: 15px 0;
    text-align: center;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

header h1 {
    margin: 0;
    font-size: 24px;
    font-weight: 400;
}

header nav ul {
    list-style: none;
    display: flex;
    justify-content: center;
    padding: 0;
    margin: 10px 0 0;
}

.nav-lists {
    background: #007bff;
}

header nav ul li {
    margin: 0 15px;
}

header nav ul li a {
    color: white;
    text-decoration: none;
    font-size: 16px;
}

header nav ul li a:hover {
    text-decoration: underline;
}

.books-heading {
    font-size: 22px;
    margin-bottom: 20px;
    color: #007bff;
    padding-bottom: 10px;
    margin-left: 35rem;
    font-size: 36px;
}

.author-heading {
    font-size: 22px;
    margin-bottom: 20px;
    color: #007bff;
    padding-bottom: 10px;
    margin-left: 35rem;
    font-size: 36px;
}

form {
    margin-bottom: 30px;
    padding: 20px;
    background-color: #e9ecef;
    border-radius: 8px;
    width: 30vw;
    margin-left: 25rem;
}

form label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold;
    color: #495057;
}

form input,
form select,
form button {
    display: block;
    width: 100%;
    padding: 10px;
    margin-bottom: 15px;
    border: 1px solid #ced4da;
    border-radius: 4px;
}

form input:focus,
form select:focus {
    border-color: #80bdff;
    outline: none;
}

form button {
    background-color: #007bff;
    color: white;
    border: none;
    cursor: pointer;
    transition: background-color 0.3s ease;
}

form button:hover {
    background-color: #0056b3;
}


ul {
    list-style: none;
    padding: 0;
}

ul li {
    background-color: #f8f9fa;
    border: 1px solid #e9ecef;
    margin-bottom: 10px;
    padding: 15px;
    border-radius: 4px;
    font-size: 16px;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.author-lists {
    margin-left: 25rem;
    width: 35vw;
}

.author-lists li:nth-child(even) {
    background-color: #e9ecef;
}

.books-lists {
    margin-left: 25rem;
    width: 35vw;
}

.books-lists li:nth-child(even) {
    background-color: #e9ecef;
}
JavaScript
// app.js code....

const express = require("express");
const bodyParser = require("body-parser");
const connectDB = require("./database/db");
const app = express();
const PORT = process.env.PORT || 3000;

// Connect to the database
connectDB();

app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("public"));

const authorRouter = require("./routes/authors");
const bookRouter = require("./routes/books");

app.use("/authors", authorRouter);
app.use("/books", bookRouter);

app.get("/", (req, res) => {
    res.redirect("/authors");
});

app.listen(PORT, (err) => {
    if (err) {
        console.log(err);
    } else {
        console.log(`Server is running on http://localhost:${PORT}`);
    }
});
JavaScript
// routes/authors.js code .....

const express = require("express");
const router = express.Router();
const Author = require("../models/author");

router.get("/", async (req, res) => {
    const authors = await Author.find({});
    res.render("authors", { authors });
});

router.post("/", async (req, res) => {
    const author = new Author({
        name: req.body.name,
    });
    await author.save();
    res.redirect("/authors");
});

module.exports = router;
JavaScript
// routes/books.js code .....

const express = require("express");
const router = express.Router();
const Book = require("../models/book");
const Author = require("../models/author");

router.get("/", async (req, res) => {
    const books = await Book.find({}).populate("author");
    const authors = await Author.find({});
    res.render("books", { books, authors });
});

router.post("/", async (req, res) => {
    const book = new Book({
        title: req.body.title,
        author: req.body.author,
    });
    await book.save();
    res.redirect("/books");
});

module.exports = router;
JavaScript
// models/author.js code .....

const mongoose = require('mongoose');

const authorSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true
    }
});

module.exports = mongoose.model('Author', authorSchema);
JavaScript
// models/book.js code .....


const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const bookSchema = new Schema({
    title: {
        type: String,
        required: true
    },
    author: {
        type: Schema.Types.ObjectId,
        ref: 'Author',
        required: true
    }
});

module.exports = mongoose.model('Book', bookSchema);
JavaScript
// database/db.js

const mongoose = require('mongoose');

const connectDB = async () => {
    try {
        await mongoose.connect('mongodb://localhost:27017/mongoose-relations', {
           
        });
        console.log('Database is connected');
    } catch (err) {
        console.error('Error connecting to the database:', err);
        process.exit(1);
    }
};

module.exports = connectDB;

Step 6: Run Your Application

To run the code write in the command prompt

node app.js

And open a new tab of your browser and type the following command to show the output.

http://localhost:3000/

Output :


Database Output:


Conclusion

In this article, we explored how to create and manage relationships between schemas using Mongoose in a Node.js application. Understanding referencing and using .populate() enables efficient handling of related data across collections. Properly modeling relationships improves data organization, reduces duplication, and enhances query performance. With these techniques, building complex and scalable MongoDB applications becomes easier and more maintainable.


Article Tags :

Similar Reads