Lesson 5
Validating Data and Handling Duplicate Entries in MongoDB Using Mongoose
Validating Data and Handling Duplicate Entries

In today’s lesson, we will learn how to ensure the data we work with is correct and how to avoid having the same data more than once in our MongoDB database using Mongoose. This is crucial because making sure our data is accurate and unique helps our applications run smoothly without errors or confusion.

What You'll Learn

In this lesson, you'll learn:

  • How to validate data in Mongoose schemas.
  • How to handle and prevent duplicate entries.
  • Practical examples to implement these concepts in a simple web application.
Step 1: Setting Up the Express.js Server and Connecting to MongoDB

Let's start by setting up an Express.js server and connecting it to our MongoDB instance. This allows us to serve our application and communicate with the database.

JavaScript
1const express = require('express'); 2const mongoose = require('mongoose'); 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 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 part of the code, we set up an Express.js server and connect to a MongoDB database named todo-app running on localhost. The useNewUrlParser and useUnifiedTopology options are included to avoid deprecation warnings. We also use the express.json() middleware to parse incoming JSON requests, which is essential for handling JSON payloads in API requests.

Step 2: Defining Mongoose Schemas

Next, let's define schemas for our data models. Schemas in Mongoose act like blueprints for the documents in your collections. This is important because it allows us to enforce a structure on our data and add validation rules.

JavaScript
1// Define schema for categories 2const categorySchema = new mongoose.Schema({ 3 name: { type: String, required: true } 4}); 5 6// Define schema for ToDo items with a reference to categories 7const todoSchema = new mongoose.Schema({ 8 task: { type: String, required: true }, 9 category: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' } 10});

In this part of the code, we define two schemas using Mongoose: one for categories and one for ToDo items. The categorySchema has a single field name which is required. The todoSchema has a task field which is a string and is required, and a category field which is a reference to a Category document. These schemas help ensure that every document in the respective collections follows a defined structure and validation rules.

Step 3: Creating Mongoose Models

After defining the schemas, we need to create models from them. Models are constructors that let us create instances of our defined schema types.

JavaScript
1// Create models 2const Category = mongoose.model('Category', categorySchema); 3const Todo = mongoose.model('Todo', todoSchema);

Here, we create models for both categories and ToDo items. Category and Todo are now Mongoose models that we can use to interact with their respective collections in the MongoDB database. They provide methods to perform CRUD (Create, Read, Update, Delete) operations on the data.

Step 4: Handling POST Requests to Create ToDo Items with Validation

Next, let’s create a route to handle adding new ToDo items. We will validate the task field and check for duplicate entries to ensure data integrity.

JavaScript
1// Route to create a new ToDo item with validation 2app.post('/add-todo', async (req, res) => { 3 const { task, categoryId } = req.body; 4 5 // Validate task 6 if (!task) { 7 return res.status(400).json({ message: 'Task is required' }); 8 } 9 10 // Check for duplicate entries 11 const existingTodo = await Todo.findOne({ task }); 12 if (existingTodo) { 13 return res.status(400).json({ message: 'Duplicate task' }); 14 } 15 16 const newTodo = new Todo({ 17 task, 18 category: categoryId 19 }); 20 21 try { 22 const savedTodo = await newTodo.save(); 23 res.status(201).json(savedTodo); 24 } catch (error) { 25 res.status(500).json({ message: 'Failed to create todo' }); 26 } 27});

In this route, we handle POST requests to /add-todo to create new ToDo items. We extract the task and category ID from the request body. First, we validate that the task field is not empty; if it is, we respond with a 400 status code and a relevant error message. Next, we check for existing ToDo items with the same task. If a duplicate is found, we return a "Duplicate task" error. If everything is in order, we create a new Todo document with the provided task and categoryId, save it to the database, and return the saved document in the response.

Step 5: Starting the Server

To make our application accessible, we need to start the Express server.

JavaScript
1app.listen(PORT, () => { 2 console.log(`Server running on http://localhost:${PORT}`); 3});

Here, we instruct the Express application to listen on the specified port (3000 in this case). When the server is running, it will log a message indicating the URL where it's accessible.

Conclusion

In this lesson, we covered how to ensure our data is valid and how to handle duplicate entries in MongoDB using Mongoose. Validating data ensures everything we save is complete and meaningful, while handling duplicates keeps our data unique and tidy. Now, you can move on to the practice exercises where you will apply these concepts yourself. Remember, practicing is key to understanding and mastering these skills. Happy coding!

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