Hamburger Icon
  • Labs icon Lab
  • Core Tech
Labs

Guided: Build a MongoDB-Powered Application with Node.js

In this lab, you will learn about MongoDB (a NoSQL database), Mongoose schemas and models, and implement a RESTful API to create, update, read, search for, and delete recipes. You will be given a recipe application to watch your changes come to life in a real codebase. By the end of this lab, you will have a deeper understanding of how MongoDB and Mongoose can be used in a Node.js application.

Labs

Path Info

Level
Clock icon Beginner
Duration
Clock icon 40m
Published
Clock icon Oct 21, 2024

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Introduction

    Welcome to the Guided: Build a MongoDB-Powered Application with Node.js lab.

    Throughout this lab, you will go over the differences between a NoSQL database and a SQL database. You will then connect a Node.js server to a local Mongo database (a NoSQL database option). Once connected, you will learn about data modeling in MongoDB. This will include building schemas to represent a Recipe and an Ingredient. Throughout, you will become familiar with MongoDB terminology like collection and document. Lastly, you will become familiar with how to perform create, read, update, and delete (CRUD) operations against your Mongo database using Mongoose. You will complete a RESTful API utilizing Node.js and Mongoose. This API will support an existing application for storing recipes. You will verify that the API works as intended by starting the application’s client and server and checking to see if data changes are persisted.

    A basic understanding of Node.js and Express will be useful to complete this lab, but it is not necessary. Any specifics around these subjects that you would need to understand the inner workings of to complete this lab will be provided. This lab will cover what a NoSQL database is as well as MongoDB and Mongoose technologies.


    Starting the Recipe Application

    To start, you have been given a recipe application created in a MERN (MongoDB, Express, React, Node.js) stack. You can create, read, update, and delete recipes using this application.

    Start the application by starting the client in one terminal and starting the server in another terminal. In one terminal, start the client by following the directions below:

    1. Change directories to the client directory.
      • Run cd client.
    2. Run npm run start to start the client.

    In another terminal, start the server by following the directions below:

    1. Change directories to the server directory.
      • Run cd server.
    2. Run npm run dev to start the server.

    Once the client and server are running, the application can be seen in the Web Browser tab if you visit http://localhost:3000. Take some time to start and visit the application. When the application has been started, you will see the photo below. Currently, no recipes can be seen in the recipe table when the application starts. This is because the application is not connected to the local Mongo database yet and the recipe API is not implemented. As the lab progresses, you will see the application become much more functional.

    Starting Recipe Application


    Helpful Tips While Completing This Lab

    There is a solution directory that you can refer to if you are stuck or want to check your implementations at any time. Keep in mind that the solution provided in this directory is not the only solution, so it is acceptable for you to have a different solution so long as the application functions as intended.

    All dependencies you will need to complete this lab have already been installed for you using Node Package Manager, npm. If you are curious about what these dependencies are, feel free to look at the package.json file in the server directory. You will learn about these dependencies throughout the lab as well.

    Just a reminder, you can stop running any foreground process in the Terminal with the command, Ctrl C.

  2. Challenge

    Introduction to MongoDB and Mongoose

    Introduction to MongoDB and Mongoose

    MongoDB has already been installed for you and is running locally. For instructions on how this can be done on your own machine, you can visit MongoDB’s self-managed deployments installation instructions. Another popular option is to use MongoDB’s cloud based service MongDB Atlas to host a MongoDB database. This will not be covered in this lab.

    Mongoose is a Node.js package that is already installed as a server dependency. To install Mongoose in another project, run npm install mongoose in a terminal. The details of why you use Mongoose alongside MongoDB will be included later in this step. For now, you will take some time to learn more about MongoDB.

    MongoDB is a NoSQL database. If you are unfamiliar with what a NoSQL database is, the next section will review the qualities of both SQL databases (also known as relational databases), and NoSQL databases (also known as non-relational databases),. This will allow you to create a meaningful definition of and understanding of the differences between the two database options.


    SQL Databases (Relational Databases)

    • Structure: SQL databases are structured and use a fixed schema with tables, rows, and columns. Columns in a table represent an attribute and rows represent a single record in the database. Each table typically represents a specific entity, and relationships between tables are defined using foreign keys. A Schema is also necessary to add any data to a table and can be cumbersome to change later on.

    • Query Language: They use Structured Query Language (SQL) for querying and managing data. SQL allows for complex queries and joins between tables.

    • Transactions: SQL databases support ACID (Atomicity, Consistency, Isolation, Durability) properties, ensuring reliable transactions.

    • Scalability: Generally, they are vertically scalable, meaning you increase capacity by adding more power to a single server.

    • Use Cases: Ideal for applications requiring complex queries, strong consistency, and structured data, such as banking systems, customer relationship management (CRM), and enterprise resource planning (ERP).

    NoSQL Databases

    • Structure: NoSQL databases are more flexible and can handle unstructured or semi-structured data. They include various data models, such as key-value stores, document stores, column-family stores, and graph databases. A Schema is not required as no structure is required by a NoSQL database. However, libraries do exist to create a Schema for NoSQL database collections like the one you will use in this lab, Mongoose.

    • Query Language: They do not have a standard query language; instead, each type of NoSQL database may have its own API or query method. Unlike the name sounds, NoSQL does not mean you can never use SQL. The term actually stands for, “Not Only SQL”.

    • Transactions: Many NoSQL databases prioritize availability and partition tolerance (as per the CAP theorem) and may offer eventual consistency instead of strict ACID compliance.

    • Scalability: NoSQL databases are typically horizontally scalable, allowing for the addition of more servers to handle increased loads.

    • Use Cases: Suitable for big data applications, real-time web apps, content management systems, and scenarios where the schema may evolve over time, such as social media platforms and IoT applications.

    Summary of SQL databases and NoSQL databases

    In summary, SQL databases are great for structured data and complex relationships, while NoSQL databases excel in flexibility and scalability for diverse and rapidly changing data types. The choice between them largely depends on the specific needs of your application.


    MongoDB Architecture

    In this lab, you are learning about the popular NoSQL database, MongoDB, for data storage. MongoDB’s structure includes collections that store documents unlike a SQL database that would be a table with rows and columns. You can loosely think of a collection like a table and a collection like a row or record within that table. This means that a collection would represent an entity in an application and a document is an instance of the entity containing various relevant fields to represent the document.

    A MongoDB document looks a lot like a JSON object (though it is technically a Binary JSON or BSON object). It is a compilation of key-value pairs where each pair is a field in the document. These fields can also contain nested documents. There is no enforced structure in any MongoDB document and you can perform any operation you would on a JSON object on a MongoDB document.

    The ability to nest documents inside of another document can make it easy to associate related documents with one collection. This means you would only have to maintain one collection unlike what would be necessary for a SQL database. The trade off is queries to fetch the nested documents can get complex and difficult to maintain.

    An example of a MongoDB document is below that represents a blogger’s profile and blog posts.

    {
      "_id": ObjectId("60d5ec49b1234567890abcdef"),
      "username": "john_doe",
      "email": "[email protected]",
      "profile_picture": "https://example.com/images/john_doe.jpg",
      "bio": "Tech enthusiast and avid traveler.",
      "created_at": ISODate("2023-09-18T10:00:00Z"),
      "blog_posts": [
        {
          "post_id": ObjectId("60d5ec49b1234567890abcde"),
          "title": "Exploring the World of NoSQL",
          "content": "NoSQL databases are becoming increasingly popular due to their flexibility and scalability. In this post, we explore various types of NoSQL databases and their use cases.",
          "date": ISODate("2023-08-01T12:00:00Z"),
          "tags": ["NoSQL", "Database", "Tech"],
          "comments": [
            {
              "comment_id": ObjectId("60d5ec49b1234567890abcdf"),
              "user": "jane_smith",
              "content": "Great insights! I love using MongoDB.",
              "date": ISODate("2023-08-02T08:30:00Z")
            },
            {
              "comment_id": ObjectId("60d5ec49b1234567890abce0"),
              "user": "mark_taylor",
              "content": "Very informative! Thanks for sharing.",
              "date": ISODate("2023-08-02T09:00:00Z")
            }
          ]
        },
        {
          "post_id": ObjectId("60d5ec49b1234567890abcdf"),
          "title": "A Day in Tokyo",
          "content": "Tokyo is a vibrant city with so much to offer. From food to culture, here’s my experience visiting the city.",
          "date": ISODate("2023-08-15T14:00:00Z"),
          "tags": ["Travel", "Tokyo", "Adventure"],
          "comments": []
        }
      ]
    }
    

    Introduction to Mongoose

    To talk to MongoDB from the Node.js application in this lab, Mongoose is a library that is a supported Node.js package. Mongoose will be used in the upcoming activity to connect to a MongoDB database from Node. In future steps, Mongoose will be used in future steps to create schemas, models, and build queries. Keep reading to learn more about Mongoose before jumping into the activity.

    Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js. It provides a straightforward way to model your data and interact with MongoDB databases, offering several useful features:

    • Schema Definition: Mongoose allows you to define schemas for your data, which serve as a blueprint for your documents. This helps enforce structure and validation.
    
    const mongoose = require('mongoose');
    
    const userSchema = new mongoose.Schema({
      username: { type: String, required: true },
      email: { type: String, required: true, unique: true },
      password: { type: String, required: true },
      createdAt: { type: Date, default: Date.now }
    });
    
    • Models: Once you've defined a schema, you can create a model based on that schema. Models are used to create and manage documents in the database.
    
    const User = mongoose.model('User', userSchema);
    
    • Data Validation: Mongoose provides built-in validation to ensure that documents meet certain criteria before being saved to the database. You can specify validation rules at the schema level.

    • Middleware: Mongoose supports middleware (also known as hooks) that can be executed at specific points in the lifecycle of a document (e.g., before saving or after removing).

    • Query Building: Mongoose offers a powerful and fluent API for building queries, making it easier to interact with the database without writing raw MongoDB queries.

    
    User.find({ username: 'john_doe' }, (err, users) => {
      if (err) console.error(err);
      console.log(users);
    });
    
    • Population: Mongoose allows you to reference documents in other collections, making it easy to work with related data. You can "populate" references to retrieve full documents.

    • Plugins: Mongoose supports plugins that can add functionality to schemas and models, allowing for reusable code.


    Activity - Connect Node to MongoDB

    1. Import Mongoose in server/server.js. Add the following line under the list of imports: import mongoose from "mongoose"
    2. Connect to the local MongoDB host and recipedb database using mongoose.connect. This can be done by adding mongoose.connect("mongodb://127.0.0.1:27017/recipedb"); underneath the imports in server/server.js.
      • Note: If the recipedb database did not exist, MongoDB would automatically create it for us when connecting. In the case of this lab, the recipedb exists and already has three recipe documents in it.

    You can test your MongoDB connection with the mongosh command. This will also print what connection string the database is running on.

    Conclusion

    In this step, you learned about MongoDB and Mongoose. In the activity, you connected the recipe application to a local instance of a MongoDB database.

  3. Challenge

    Data Modeling with Mongoose

    Data Modeling with Mongoose

    Mongoose allows you to define schemas for your data. These schemas can enforce certain document structures even though MongoDB is a NoSQL database. Mongoose also allows you to create models based on schemas. These models can be used to perform CRUD operations on documents in a collection.

    In this step, you will define the Recipe and Ingredient schemas. After these schemas are defined, you will create a RecipeModel that will be used to create, update, read, and delete recipe documents in future steps.

    You will not need to create a model for the Ingredient schema. This is because you will only ever store an ingredient as a nested document in a recipe, so you will not need to use a model to query ingredients. Lastly, you will export the schemas and model you create.


    Activity 1 - Define and Export an Ingredient Schema

    In server/models/ingredient.js follow the steps below to define an Ingredient Schema.

    1. Import Mongoose at the top of the file.
    2. Store mongoose.Schema in a constant variable called Schema.
    3. Create a new Schema object with the properties below and store this object in a constant variable titled IngredientSchema.
      • quantity: Number
      • metric: String
      • ingredient: String
      • Note: Schema is passed a Javascript object with key-value pairs. The object will then be the enforced structure of documents that are of the created Schema type.
    4. Export IngredientSchema
    Example recipe.js After Activity 1
    // Step 3 - Activity 1.1 Import mongoose
    import mongoose from "mongoose";
    // Step 3 - Activity 1.2 mongoose Schema variable
    const Schema = mongoose.Schema;
    
    // Step 3 - Activity 1.3 Define IngredientSchema
    const IngredientSchema = new Schema({
      quantity: Number,
      metric: String,
      ingredient: String,
    });
    
    // Step 3 - Activity 1.4 export IngredientSchema
    export { IngredientSchema };
    

    Activity 2 - Define and Export a Recipe Schema

    In server/models/recipe.js follow the steps below to define a Recipe Schema.

    1. Import Mongoose at the top of the file.
    2. Import IngredientSchema from ./ingredient.js
    3. Store mongoose.Schema in a constant variable called Schema.
    4. Create a new Schema object with the properties below and store this object in a constant variable titled RecipeSchema.
      • title: String
      • instructions: String
      • ingredients: [IngredientSchema] - This is an array of ingredients
      • prepTime: Number
      • cookTime: Number
    5. Export RecipeSchema
    Example recipe.js After Activity 2
    // Step 3 - Activity 2.1 Import mongoose
    import mongoose from "mongoose";
    // Step 3 - Activity 2.2 Import IngredientSchema
    import { IngredientSchema } from "./ingredient.js";
    
    // Step 3 - Activity 2.3 mongoose Schema variable
    const Schema = mongoose.Schema;
    
    // Step 3 - Activity 2.4 Define RecipeSchema
    const RecipeSchema = new Schema({
      title: String,
      instructions: String,
      ingredients: [IngredientSchema],
      prepTime: Number,
      cookTime: Number,
    });
    
    // Step 3 - Activity 2.5 Export RecipeSchema
    export { RecipeSchema };
    

    Activity 3 - Define a Recipe Model

    Models that can be used to perform queries are defined through Mongoose’s Schema interface. Since you created RecipeSchema in the previous activity, you can create a recipe model.

    1. Above the export statement in server/models/recipe.js, call mongoose.model to create a recipe model. Store the recipe model in a constant variable called RecipeModel.
      • Note: The database can be accessed through mongoose.model. The first argument passed to mongoose.model is the singular name of the collection your model is for. In this case, it is ”Recipe”. Mongoose tries to find a collection with the plural version of this parameter, “Recipes”, and if it does not find one, it will create one. The second parameter is the schemadocumentsin thiscollectionshould follow. You will passRecipeSchema` as the second parameter.
    2. Export RecipeModel
    Example recipe.js After Activity 3
    import mongoose from "mongoose";
    import { IngredientSchema } from "./ingredient.js";
    
    const Schema = mongoose.Schema;
    
    const RecipeSchema = new Schema({
      title: String,
      instructions: String,
      ingredients: [IngredientSchema],
      prepTime: Number,
      cookTime: Number,
    });
    
    // Step 3 - Activity 3.1 Create RecipeModel
    const RecipeModel = mongoose.model("Recipe", RecipeSchema);
    
    // Step 3 - Activity 3.2 Export RecipeModel
    export { RecipeSchema, RecipeModel };
    

    Conclusion

    In this step, you have created schemas and a model using mongoose. Continue on to begin querying your MongoDB database.

  4. Challenge

    Read Documents From the Recipe Collection with Mongoose

    Read Documents From the Recipe Collection with Mongoose

    In this step, you will finish implementing the GET /recipes and GET /recipes/:id endpoints in server/server.js. This will include selecting all recipe documents, filtering the selection of recipe documents on title, and selecting a recipe document based on its id.


    Activity 1 - Get All Recipes

    1. Import RecipeModel from ./models/recipe.js. This is necessary to use the model to perform queries against the ”Recipes” collection. Add import { RecipeModel } from "./models/recipe.js"; next to the existing imports.
    2. Inside the GET /recipes endpoint, you will notice a try catch block. Inside the try block, select all recipe documents in the Recipes collection.
      • Note: To select all documents in the Recipes collection, you will need to pass an empty document, {} as the query filter parameter to the first argument of the RecipeModel’s find method.
    3. Await the results of the find method as all Mongoose queries are asynchronous calls.
    4. Store the results of the find method in the results variable.
    Example GET /recipes Endpoint After Activity 1
    
    app.get("/recipes", query("title").escape(), async (req, res, next) => {
      const title = req.query.title;
      try {
        let results;
        // Step 4 - Activity 1.2 - 1.4 Get All Recipes
        results = await RecipeModel.find({});
        res.status(200).json(results);
      } catch (error) {
        next(error);
      }
    });
    

    You will notice that the GET /recipes endpoint sends back a 200 status code and the results as JSON. This means that if you visit the recipe application while it is running and refresh the home page, you should now see three different recipes in the recipes table. This is proof that your endpoint is fetching data from the MongoDB database. You can also take note that the application would raise an error if an error would occur while fetching data because of the query being wrapped in a try catch block.

    Take some time to visit the application now, it should look like the picture below since the Recipes collection has already been seeded with data for you. You can see that search, create, edit, and delete functionality still needs to be implemented for the application to function as intended.

    Recipe Application After Step 4 Activity 1


    Activity 2 - Get All Recipes That Have the Title URL Query In the Recipe Title

    1. Inside the try block in the GET /recipes endpoint, write an if else statement. The if block will be entered if the variable title is defined. The title variable is created for you at the top of the end point and is a query parameter on the request’s url.
    2. Move the results = await RecipeModel.find({}); line of code that you wrote in the previous activity into the else case.
    3. Select all recipe documents in the Recipes collection with title in the recipe’s title.
      • Note: This requires using the query filter parameter that is passed to the find method. The query filter parameter determines the select criteria. To find all documents that contain title in the recipe document’s title, you need to pass the following object: { title: new RegExp(title, “i”) }
    4. Await the results of the find method.
    5. Store the results of the find method in the results variable.
    Example GET /recipes Endpoint After Activity 2
    
    app.get("/recipes", query("title").escape(), async (req, res, next) => {
      const title = req.query.title;
      try {
        let results;
        // Step 4 - Activity 2.1 Create an If Else Block Based On If Title Is Defined
        if (title) {
          // Step 4 - Activity 2.3 - 2.5 Find recipes with title in their titles
          results = await RecipeModel.find({
            title: new RegExp(title, "i"),
          });
          // Step 4 - Activity 2.1 Create an If Else Block Based On If Title Is Defined
        } else {
          // Step 4 - Activity 2.2 Move Get All Recipes Into the Else Case
          results = await RecipeModel.find({});
        }
        res.status(200).json(results);
      } catch (error) {
        next(error);
      }
    });
    
    

    Because the variable results is conditionally set based on if a title is passed to the endpoint or not, this endpoint can now respond to two different requests for data. One request wants to fetch all the recipes and the other request wants to fetch all recipes that have title in their title.

    Refresh the application in the Web Browser and you should now be able to search the applications based on title. This may look like the picture below.

    Recipe Applicatoin Search Ability


    Activity 3 - Get A Recipe By Its ID

    1. Import ObjectID from ”mongodb” next to the existing imports. This will look like import { ObjectId } from "mongodb"; This module is necessary to convert string or number ids into a MongoDB ObjectID data type. This conversion will be necessary to actually perform a search for a recipe collection based on its id.
    2. Inside the try block in the GET /recipes/:id endpoint, store the result of ObjectId.createFromHexString(req.params.id); in a constant variable called, id.
    3. Inside the try block in the GET /recipes/:id endpoint, await the result of RecipeModel.findById(id) and save it to the constant variable called, result. The constant variable result is current just being set to an empty object, it is up to you to change that.
    Example GET /recipe/:id Endpoint After Activity 3
    
    app.get("/recipes/:id", async (req, res) => {
      try {
        // Step 4 - Activity 3.2
        const id = ObjectId.createFromHexString(req.params.id);
        // Step 4 - Activity 3.3
        const result = await RecipeModel.findById(id);
        res.status(200).json(result);
      } catch (error) {
        next(error);
      }
    });
    

    As mentioned before, result is sent on as JSON with a status code of 200. Refresh the recipe application, and you will be able to click on each recipe’s title in the table to see the specifics around the recipe on a new page. This will load a page like the photo below. This verifies that you can query the MongoDB database for just one recipe at a time by its ID.

    Recipe Application Viewing One Recipe


    Conclusion

    In this step, you were able to read data from the local MongoDB database instance. You also verified that the code you wrote is working correctly by visiting the recipe application in the Web Browser.

  5. Challenge

    Update a Recipe Document with Mongoose

    Update a Recipe Document with Mongoose

    You will now finish implementing the PUT /recipes/:id endpoint. This will include creating a MongoDB ObjectId object from the requests id parameter, finding the recipe document with the corresponding id, setting the recipe’s fields to match what was sent in requests body, and saving the recipe document.

    Activity - Update a Recipe

    1. Inside the try block in the PUT /recipes/:id endpoint, store the result of ObjectId.createFromHexString(req.params.id); in a constant variable called, id.
    2. Save the request’s body, accessed through req.body to a constant variable called, body.
    3. Find the recipe with the corresponding id, like you did in the previous step. Assign the result to a variable called, result. This variable is already created for you, just change the assignment from the empty object to what you get back from Mongoose's findById command.
      • Note: The result variable should be created with the let keyword because it is not a constant variable and will change.
    4. Set result’s title to body’s title.
      • Hint: This assignment will look like result.title = body.title;. Future assignments will look similar except with different field names.
    5. Set result’s instructions to body’s instructions.
    6. Set result’s ingredients to body’s ingredients.
    7. Set result’s prepTime to body’s prepTime.
    8. Set result’s cookTime to body’s cookTime.
    9. Await the result of calling save on result.
      • Remember: result is a recipe document in the Recipes collection. By saving result, you are updating the corresponding document.
    Example PUT /recipes/:id Endpoint After Activity 1
    
    app.put("/recipes/:id", async (req, res, next) => {
      try {
        // Step 5 - Activity 1.1 Change The Request Parameter ID To a MongoDB ObjectID
        const id = ObjectId.createFromHexString(req.params.id);
        // Step 5 - Activity 1.2 Save the body of the request to a variable
        const body = req.body;
        // Step 5 - Activity 1.3 Find the Corresponding Recipe
        let result = await RecipeModel.findById(id);
        // Step 5 - Activity 1.4 Update the Recipe's Title
        result.title = body.title;
        // Step 5 - Activity 1.5 Update the Recipe's instructions
        result.instructions = body.instructions;
        // Step 5 - Activity 1.6 Update the Recipe's ingredients
        result.ingredients = body.ingredients;
        // Step 5 - Activity 1.7 Update the Recipe's prepTime
        result.prepTime = body.prepTime;
        // Step 5 - Activity 1.8 Update the Recipe's cookTime
        result.cookTime = body.cookTime;
        // Step 5 - Activity 1.9 Save the Updated Recipe
        await result.save();
        res.status(200).json(result);
      } catch (error) {
        next(error);
      }
    });
    

    The update endpoint responds with a status code of 200 and the JSON of the new recipe if the update operation finished with no errors. Refresh the recipe application and you will now be able to edit a recipe and persist the changes. This is proof that your endpoint is making updates to documents in your database.

    Conclusion

    You now have performed update operations to documents in a MongoDB collection.

  6. Challenge

    Delete a Recipe Document with Mongoose

    Delete a Recipe Document with Mongoose

    In this step, you will finish implementing the DELETE /recipes/:id endpoint. Like previous steps, you will start by converting the request id parameter into a MongoDB ObjectID. Then, you will use the method deleteOne to delete the corresponding recipe.

    Activity - Delete a Recipe

    1. Inside the try block in the PUT /recipes/:id endpoint, store the result of ObjectId.createFromHexString(req.params.id); in a constant variable called, id.
    2. Await the result of RecipeModel.deleteOne({ _id: id }); to delete the corresponding recipe.
      • Note: You will notice the object passed to deleteOne has a key titled, _id. The title and value of this key is what MongoDB adds when it creates a new document. It is similar to a primary key in a SQL database’s table.
    Example DELETE /recipes/:id Endpoint After Activity 1
    
    app.delete("/recipes/:id", async (req, res, next) => {
      try {
        // Step 6 - Activity 1.1 Change The Request Parameter ID To a MongoDB ObjectID
        const id = ObjectId.createFromHexString(req.params.id);
        // Step 6 - Activity 1.2 Delete a Recipe With The Corresponding ID
        await RecipeModel.deleteOne({ _id: id });
        res.status(200).json({ message: `Recipe successfully deleted` });
      } catch (error) {
        next(error);
      }
    });
    

    If you look at the parts of the delete endpoint that were given to you, you will notice if the operation successfully completes the endpoint responds with a status code of 200 and a message. Refresh the recipe application, you now can remove recipes by clicking the delete button and the change is persisted all the way through to the database.

    Conclusion

    In this step, you programmed a way to delete documents from your MongoDB database using Mongoose’s RecipeModel. This operation would have also been possible with the findByIdAndDelete command.

  7. Challenge

    Create a Recipe Document with Mongoose

    Create a Recipe Document with Mongoose

    Now you will finish implementing the POST /recipes endpoint. This will be simple using the request’s body and the create method on a Mongoose model.

    Activity - Create a Recipe

    1. Inside the try block in the POST /recipes endpoint at the top, assign req.body to a constant variable called, body.
    2. Update the assignment of the result variable to be the result from awaiting the result of await RecipeModel.create(body);.
    Example POST /recipes/ Endpoint After Activity 1
    
    app.post("/recipes", async (req, res, next) => {
      try {
        // Step 7 - Activity 1.1 Store the Reuqest's Body in a Variable
        const body = req.body;
        // Step 7 - Activity 1.2 
        const result = await RecipeModel.create(body);
        res.status(200).json(result);
      } catch (error) {
        next(error);
      }
    });
    

    The endpoint responds with a status code of 200 and the JSON of the result from creating the recipe if it encounters no errors. This means if you refresh the recipe application, you should now be able to create recipes and see that they are added to the recipe table. When you refresh once more, new recipes should remain in the table and that is proof that they are being persisted to the database.

    Conclusion

    You have now created new documents in a MongoDB collection.

  8. Challenge

    Conclusion

    Conclusion

    Throughout this lab, you became familiar with what a NoSQL database is and how it differs from SQL databases. This lab covered the specific NoSQL database, MongoDB. You worked with Mongoose, a package built to support interactions with MongoDB. You used Mongoose to create collection schemas and created a recipe model to perform CRUD operations and enforce schemas. You implemented a RESTful API to perform CRUD operations within the recipe collection. You have the opportunity to see your API work in live time by running the recipe application’s client and server and visiting the application. Within the application you could search for recipes as well as create, update, and delete recipes. This is a great example of how MongoDB and Mongoose are used in Node.js applications to create server APIs.

Jaecee is an associate author at Pluralsight helping to develop Hands-On content. Jaecee's background in Software Development and Data Management and Analysis. Jaecee holds a graduate degree from the University of Utah in Computer Science. She works on new content here at Pluralsight and is constantly learning.

What's a lab?

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.