Tutorial

How To Perform CRUD Operations with Mongoose and MongoDB Atlas

Updated on March 22, 2021
Default avatar

By Joshua Hall

How To Perform CRUD Operations with Mongoose and MongoDB Atlas

Introduction

Mongoose is one of the fundamental tools for manipulating data for a Node.js and MongoDB backend.

In this article, you will be looking into using Mongoose with the MongoDB Atlas remote database. The example in this tutorial will consist of a list of food and their caloric values. Users will be able to create new items, read items, update items, and delete items.

Prerequisites

Downloading and installing a tool like Postman is recommended for testing API endpoints.

This tutorial was verified with Node v15.3.0, npm v7.4.0, express v4.17.1, mongoose v5.11.12, and MongoDB v4.2.

MongoDB Atlas Setup

This project also requires a MongoDB Atlas account.

After creating an account and signing in, follow these steps to deploy a free tier cluster.

Once you have set a cluster, a database user, and an IP address you will be prepared for later acquiring the connection string as you set up the rest of your project.

Step 1 — Setting Up the Project

In this section, you will create a directory for your project and install dependencies.

Create a new directory for your project:

  1. mkdir mongoose-mongodb-atlas-example

Navigate to the newly created directory:

  1. cd mongoose-mongodb-atlas-example

At this point, you can initialize a new npm project:

  1. npm init -y

Next, install express and mongoose:

  1. npm install express@4.17.1 mongoose@5.11.12

At this point, you will have a new project with express and mongoose.

Step 2 — Setting Up the Server

In this section, you will create a new file to run the Express server, connect to the MongoDB Atlas database, and import future routes.

Create a new server.js file and add the following lines of code:

server.js
const express = require("express");
const mongoose = require("mongoose");
const foodRouter = require("./routes/foodRoutes.js");

const app = express();

app.use(express.json());

mongoose.connect(
  "mongodb+srv://madmin:<password>@clustername.mongodb.net/<dbname>?retryWrites=true&w=majority",
  {
    useNewUrlParser: true,
    useFindAndModify: false,
    useUnifiedTopology: true
  }
);

app.use(foodRouter);

app.listen(3000, () => {
  console.log("Server is running...");
});

Pay attention to the connection string. This is the connection string that is provided by MongoDB Atlas. You will need to replace the administrator account (madmin), password, cluster name (clustername), and database name (dbname) with the values that are relavent to your cluster:

mongodb+srv://madmin:<password>@clustername.mongodb.net/<dbname>?retryWrites=true&w=majority

mongoose.connect() will take the connection string and an object of configuration options. For the purpose of this tutorial, the useNewUrlParser, useFindAndModify, and useUnifiedTopology configuration settings are necessary to avoid a deprecation warning.

At this point, you have the start of an Express server. You will next need to define the schema and handle routes.

Step 3 — Building the Schema

First, you will need to have a pattern to structure your data on to and these patterns are referred to as schemas. Schemas allow you to decide exactly what data you want and what options you want the data to have as an object.

In this tutorial, you will use the mongoose.model method to make it usable with actual data and export it as a variable you can use in foodRoutes.js.

Create a new models directory:

  1. mkdir models

Inside of this new directory, create a new food.js file and add the following lines of code:

./models/food.js
const mongoose = require("mongoose");

const FoodSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    trim: true,
    lowercase: true,
  },
  calories: {
    type: Number,
    default: 0,
    validate(value) {
      if (value < 0) throw new Error("Negative calories aren't real.");
    },
  },
});

const Food = mongoose.model("Food", FoodSchema);

module.exports = Food;

This code defines your FoodSchema. It will consist of a name value that is of type String, it will be required, trim any whitespace, and set to lowercase characters. It will also consist of a calories value that is of type Number, it will have a default of 0, and validate to ensure no negative numbers are submitted.

Step 4 — Building the Read Route

Once you have your data model set up, you can start setting up routes to use it. This will utilize various querying functions available through Mongoose.

You will start by reading all foods in the database. At this point, it will be an empty array.

Create a new routes directory:

  1. mkdir routes

Inside of this new directory, create a new foodRoutes.js file and add the following lines of code:

./routes/foodRoutes.js
const express = require("express");
const foodModel = require("../models/food");
const app = express();

app.get("/foods", async (request, response) => {
  const foods = await foodModel.find({});

  try {
    response.send(foods);
  } catch (error) {
    response.status(500).send(error);
  }
});

module.exports = app;

This code establishes a /foods endpoint for GET requests (note the plural ‘s’). The Mongoose query function find() returns all objects with matching parameters. Since no parameters have been provided, it will return all of the items in the database.

Since Mongoose functions are asynchronous, you will be using async/await. Once you have the data this code uses a try/catch block to send it. This will be useful to verify the data with Postman.

Navigate to the root of your project directory and run your Express server with the following command in your terminal:

  1. node server.js

In Postman, create a new Read All Food request. Ensure the request type is set to GET. Set the request URL to localhost:3000/foods. And click Send.

Note: If you need assistance navigating the Postman interface for requests, consult the official documentation.

The Postman results will display an empty array.

Step 5 — Building the Create Route

Next, you will build the functionality to create a new food item and save it to the database.

Revisit the foodRoutes.js file and add the following lines of code between app.get and module.exports:

./routes/foodRoutes.js
// ...

app.post("/food", async (request, response) => {
  const food = new foodModel(request.body);

  try {
    await food.save();
    response.send(food);
  } catch (error) {
    response.status(500).send(error);
  }
});

// ...

This code establishes a /food endpoint for POST requests. The Mongoose query function .save() is used to save data passed to it to the database.

In Postman, create a new request called Create New Food. Ensure the request type is set to POST. Set the request URL to localhost:3000/food.

In the Body section, select raw and JSON. Then, add a new food item by constructing a JSON object with a name and calories:

{
  "name": "cotton candy",
  "calories": 100
}

After sending the Create New Food request, send the Read All Food request again. The Postman results will display the newly added object.

Step 6 — Building the Update Route

Every object created with Mongoose is given its own _id and you can use this to target specific items. It will be a mix of alphabetical characters and letters. For example: 5d1f6c3e4b0b88fb1d257237.

Next, you will build the functionality to update an existing food item and save the changes to the database.

Revisit the foodRoutes.js file and add the following lines of code between app.post and module.exports:

./routes/foodRoutes.js
// ...

app.patch("/food/:id", async (request, response) => {
  try {
    await foodModel.findByIdAndUpdate(request.params.id, request.body);
    await foodModel.save();
    response.send(food);
  } catch (error) {
    response.status(500).send(error);
  }
});

// ...

This code establishes a /food/:id endpoint for PATCH requests. The Mongoose query function .findByIdAndUpdate() takes the target’s id and the request data you want to replace it with. Then, .save() is used to save the changes.

In Postman, create a new request called Update Food. Ensure the request type is set to PATCH. Set the request URL to localhost:3000/food/<id>, where id is the identifying string of the food you created previously.

In the Body section, select raw and JSON. Then, modify your food item by constructing a JSON object with a name and calories:

{
  "calories": "999"
}

After sending the Update Food request, send the Read All Food request again. The Postman results will display the object with modified calories.

Step 7 — Building the Delete Route

Finally, you will build the functionality to remove an existing food item and save the changes to the database.

Revisit the foodRoutes.js file and add the following lines of code between app.patch and module.exports:

./routes/foodRoutes.js
// ...

app.delete("/food/:id", async (request, response) => {
  try {
    const food = await foodModel.findByIdAndDelete(request.params.id);

    if (!food) response.status(404).send("No item found");
    response.status(200).send();
  } catch (error) {
    response.status(500).send(error);
  }
});

// ...

This code establishes a /food/:id endpoint for DELETE requests. The Mongoose query function .findByIdAndDelete() takes the target’s id and removes it.

In Postman, create a new request called Delete Food. Ensure the request type is set to DELETE. Set the request URL to localhost:3000/food/<id>, where id is the identifying string of the food you created previously.

After sending the Delete Food request, send the Read All Food request again. The Postman results will display an array without the item that was deleted.

Note: Now that you have completed this tutorial, you may wish to Terminate any MongoDB Atlas clusters that you are no longer using.

At this point, you have an Express server using Mongoose methods to interact with a MongoDB Atlas cluster.

Conclusion

In this article, you learned how to use Mongoose methods you can quickly make and manage your backend data.

If you’d like to learn more about Node.js, check out our Node.js topic page for exercises and programming projects.

If you’d like to learn more about MongoDB, check out our MongoDB topic page for exercises and programming projects.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Joshua Hall

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
3 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

On Step 6, why do you have to run model.save()? Isn’t findByIdAndUpate() supposed to update by itself the document (if found)?

For deletion, the findByIdAndDelete() function already performs the deletion, so why did the findByIdAndUpdate() function have a following save()?

The save() call in the document creation makes sense, since you’re instantiating a new model (new doc) and then saving it, but it doesn’t make sense to me in the update.

Thanks!

Gooday sir Do you have a git repo for this. I wud much appreciate if you have it hosted too Or u want me to figure it out too

The challenge I been having with these tutorials is transitioning from ‘localhost’ to remote host. That’s why I asked you the above questions

Great tutorial!

Think I may have found one small error: In “File Setup” you refer to the file ./models/FoodModel.js but later refer to the same file as ./models/food.js. Perhaps, I missed something obvious? Thanks for the very helpful tutorial.

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel