Introduction to Mongoose and how to work with MongoDb with Mongoose


Reading time: 35 minutes | Coding time: 10 minutes

In this article, we will explore Mongoose and get an idea of using it with MongoDB through a demo. We will learn how to create, update, delete and read documents in MongoDB.

⭐ What is Mongoose and Why use it ?


Express
Mongoose is an Object Data Modelling Library(ODM) for MongoDB and Node.js, providing a higher level of abstraction.

It is similar to the relationship between Express and Node, as Express is a layer of abstraction over Node.js while Mongoose is a layer of abstraction over the regular MongoDB driver.

And basically, an object data modeling library is simply a way for us to write our JavaScript code that will interact with the database.
We use Mongoose over several other MongoDB drivers, because of the out of box functionalities, that allows for faster and simpler development of our applications.

Some of the features that Mongoose provides us are schemas to structure and model our data and relationship, easy data validation, simple query APIs and much more.

⭐ Getting Started - Installing Mongoose and Connecting it to our Database


  1. Create a new project, and use the command npm init to initialize the project.
npm init

mogoose-1

  1. To install Mongoose, use the command npm install mongoose@5, where 5 refers to the mongoose version that we'll be using.
npm install mongoose@5
  1. Now, let us connect our MongoDb database to Mongoose

a. Create a file called server.js and include the following code -

// Requiring mongoose
const mongoose = require("mongoose");

// Connecting to Database
const Db = "mongodb://localhost:27017/recipes";

Here, we have first created an instance of mongoose and then saved our MongoDb connection string in the Db object. Make sure that the mongo shell is running, while you do operations on the database.

b. Connecting to the database -

Include the following code -

mongoose
  .connect(Db, {
    useNewUrlParser: true,
    useCreateIndex: true,
    useFindAndModify: false
  })
  .then(con => {
    console.log(con.connections);
    console.log(" DB connection successful !");
  });

Here, mongoose.connect() returns a promise, we have used then here to receive the promise, but we can also use async-await here.

  1. Now, run node server.js to run the app. We get the following output in the console -
node server.js

mongoose-2

So, Mongoose is now successfully connected to our database.

⭐ Mongoose Schema vs Model


In Mongoose, a schema is where we model our data, where we describe the structure of the data, the default values, the constraints, and validation.

We then take that schema and create a model out of it. The model serves as a wrapper around the schema, which allows us to interface with the database to create, delete, update, and read documents.

Now, Mongoose is all about Models and a model is like a blueprint that we use to create, query, update and delete documents. To perform any CRUD operations, we need a Mongoose model, and to create a model, we need a schema.

For instance, let us create a schema for Recipes. A recipe will surely have a name, some rating, and time duration.

const recipeSchema = new mongoose.Schema ();

Here, we have created an instance of the mongoose schema, but it isn't completed yet. We need to pass in the object of the required schema to it.

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

Here, we have specified our first attribute, or the first field for the document, name. Mongoose uses native JavaScript datatypes, so here we can specify any data type - String, Number, Array, Date or Boolean. This is the most basic way of describing our data. Now, let us add fields for rating and time duration also.

const recipeSchema = new mongoose.Schema(
{
name:
{
type:String,
required:true
},
rating : Number,
timeDuration : Number
}

Note how we have made the name as required, but the other two fields need not be necessarily there.
Now, for the required attribute, we can also pass in the error statement that we want to be displayed when we're missing the field. We just need to pass an array to the required field, as follows -

const recipeSchema = new mongoose.Schema(
{
name:
{
type:String,
required:[true,' Recipe must have a name']
}

We can also specify default values, for instance, let's save the default value of our rating as 4.5.

rating:
{
type:Number,
default:4.5
}

We can also use the unique property to ensure the recipes name are unique, so our document looks like this now -

const recipeSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    unique: true
  },
  rating: {
    type: Number,
    default: 4.5
  },
  timeDuration: Number
});

So, this is our very basic schema, and let's now create a model out of it.

const Recipe = mongoose.model('Recipe',recipeSchema);

📝 Creating Documents -


We use our Recipe modal to create a new document, just like we create an object using classes in Javascript.

To create a new recipe with values :

name: "Veg. Grilled Cheese Burger"
rating: 4.5
duration: 2

To create this as a document, include the following code -

const testRecipe = new Recipe({
  name: "Veg. Grilled Cheese Burger",
  rating: 4.5,
  timeDuration: 2
});

This creates a new document and stores it to testRecipe. To save the document, we use the save() method.

testRecipe
  .save()
  .then(doc => console.log(doc))
  .catch(err => console.log("ERROR :", err));

save() method also returns a promise when we save the document.

Now, run the app - node server.js, we get the following output in the console.

mongoose-3

You may verify that the document is saved, by running db.recipe.find() in the mongo shell, to see all the documents in the database.

mongoose-4

Now, let us try to save another document to the collection -

const testRecipe2 = new Recipe({ name: "Pasta", timeDuration: 1 });

testRecipe2
.save()
.then(doc => console.log(doc))
.catch(err => console.log("ERROR :", err));

Now, if we try to run node server.js, we get the following error -

mongoose-5

This is because our program tries to save the previous document again in the database, but if you remember we have specified in the schema that the name of the recipe should be unique. Hence, mongoose throws an error.

So, to save the next document, comment out the code for the previous document.

Now, run the app, and we get the following output on the terminal -

mongoose-6

And also from the mongo shell, we can verify that our document has been saved -

m7

📝 Reading documents -


We have the find() method to read documents from a collection. To read documents, we use all of the methods directly on the model object.

For instance, to read all documents from the Recipe model, include the following code -

const recipes = Recipe.find()
.then(docs => console.log(docs))
.catch(err => console.log("ERROR :", err));

This gives the following output -

m8

To search for a particular document, we may specify the required attributes and values and pass it as an object to the find() method.

For instance, if we want to find the recipe with name 'Pasta', the following code would work -

const recipes = Recipe.find({ name: "Pasta" })
.then(docs => console.log(docs))
.catch(err => console.log("ERROR :", err));

This gives the following output -

m9

📝 Updating documents -


To update a document, we need its _id which in our case is automatically created by MongoDB.

To update a document, we use the method findByIdAndUpdate() on the model object. The method takes in the _id as a parameter.
For instance - to update the rating of Veg. Grilled Cheese Burger, include the following code in the program -

const recipes = Recipe.findByIdAndUpdate("5d794e71922481309c8e6883", {
rating: 3.5
})
.then(doc => console.log(doc))
.catch(err => console.log(err));

Here, "5d794e71922481309c8e6883" is the id of the document. We can verify if the document has been updated using db.recipe.find() in the mongo shell.

We get the following output -

m10

The rating for Veg. Grilled Cheese Burger has been successfully updated.

📝 Deleting Documents -


Deleting a document through Mongoose is very easy. We use the method findByIdAndDelete and pass the id of the document to be deleted as the parameter -

For instance, if we want to delete our first document, include the following code -

const recipes = Recipe.findByIdAndDelete("5d794e71922481309c8e6883").

This deletes the document with _id="5d794e71922481309c8e6883". We may verify the delete operation through our mongo shell.

We get the following results-

m11

The document has been successfully deleted.

And we are all done ! 🎉

⭐ References/ Further Reading -


  1. https://mongoosejs.com/
  2. https://www.npmjs.com/package/mongoose