Lesson 4
Creating Relationships Between Models
Creating Relationships Between Models

In the past lessons, we learned how to set up MongoDB with Express.js, define Mongoose schemas and models, and manage ToDo items. Today, we'll take a step further and learn about creating relationships between models. Models in MongoDB help us structure our data, but sometimes we need to connect different types of data, like linking todo items to their categories. Creating these connections is crucial for building more complex applications, enabling more detailed queries, such as finding all tasks in a specific category or aggregating tasks by categories in a task management app.

What You'll Learn

In this lesson, you'll learn:

  • What relationships between models are
  • How to create and use references between models
  • How to populate data from related models
Step 1: Connecting to MongoDB

First, we need to connect to MongoDB. We've done this multiple times in previous lessons, so here's the code snippet for reference:

JavaScript
1const mongoose = require('mongoose'); 2const express = require('express'); 3 4const app = express(); 5const PORT = 3000; 6 7// Set mongoose strictQuery to true to suppress deprecation warning 8mongoose.set('strictQuery', true); 9 10// Connect to MongoDB, ensure your MongoDB server is running 11mongoose.connect('mongodb://127.0.0.1:27017/todo-app', { 12 useNewUrlParser: true, 13 useUnifiedTopology: true, 14}) 15.then(() => console.log("Connected to MongoDB")) 16.catch((error) => console.error("Failed to connect to MongoDB:", error)); 17 18app.use(express.json());

In this code, we set up the Express application, and connect to our MongoDB database.

Step 2: Defining Schemas and Models

Next, we'll define the schemas for our Category and ToDo models.

JavaScript
1// Define schema for categories 2const categorySchema = new mongoose.Schema({ 3 name: { 4 type: String, 5 required: true, 6 trim: true, 7 minLength: 3, 8 maxLength: 50 9 } 10}); 11 12// Create Category model 13const Category = mongoose.model('Category', categorySchema);

In the above schema definition, trim option removes any whitespace from the input. minLength and maxLength ensure the category name stays within the specified length range (3 to 50 characters).

Now, we'll create the ToDo model with a reference to the Category model.

JavaScript
1const todoSchema = new mongoose.Schema({ 2 task: { type: String, required: true }, 3 category: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' } 4}); 5 6// Create ToDo model 7const Todo = mongoose.model('Todo', todoSchema);

In this step, the category field in our ToDo schema is of type ObjectId and references the Category model, allowing us to link ToDo items with specific categories.

Step 3: Creating Routes

Now, we’ll set up routes to handle CRUD operations for both Category and ToDo models.

Routes for Categories:

JavaScript
1// Routes for categories 2app.get('/categories', async (req, res) => { 3 const categories = await Category.find(); 4 res.send(categories); 5}); 6 7app.post('/categories', async (req, res) => { 8 const category = new Category(req.body); 9 await category.save(); 10 res.send(category); 11});

These routes allow us to get a list of categories and create new categories.

Routes for ToDo Items:

JavaScript
1// Routes for todo items 2app.get('/todos', async (req, res) => { 3 const todos = await Todo.find().populate('category'); 4 res.send(todos); 5}); 6 7app.post('/todos', async (req, res) => { 8 const todo = new Todo(req.body); 9 await todo.save(); 10 res.send(todo); 11});

These routes allow us to:

  • Retrieve a list of todo items, with populated category data, to provide more detailed and comprehensive information.
  • Create new todo items, including their category references, to ensure each task is associated with the appropriate category.

The .populate('category') method converts the ObjectId in the category field into the actual Category document it references, providing richer query results by including full category details.

Step 4: Error Handling Middleware

To handle errors gracefully, we add an error handling middleware.

JavaScript
1// Error handling middleware 2app.use((err, req, res, next) => { 3 console.error(err.stack); 4 res.status(500).send('Something broke!'); 5});

Finally, let's start the Express server.

JavaScript
1// Start Express server 2app.listen(PORT, () => { 3 console.log(`Server listening on port ${PORT}`); 4});
Conclusion

In this lesson, we learned how to create relationships between models in Mongoose. To recap, we began by understanding references and their importance, created Category and ToDo models, added references to link them, updated our routes to handle category-linked tasks, and used the populate method to fetch comprehensive data. These skills are essential for building complex applications where different types of data need to be connected.

Now, it's time to practice these skills with some exercises. These exercises will help reinforce your understanding and make you more confident in working with relationships between models. Happy coding!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.