How to connect Node.JS Express app to MongoDB using mongoose?

How to connect Node.JS Express app to MongoDB using mongoose?

In this short tutorial, I will go over how to connect your nodejs/express app to MongoDB database using mongoose.

At the end, in the "Discussion" section, I will go over why I wrote the code in this format and my thought process. So make sure to check that as well.

(This tutorial is a tutorial on mongoose, so I will assume that you already have a basic understanding of express and npm. If you are a complete beginner, this article maybe a bit too fast paced.)

For this tutorial, I will assume that you already have MongoDB installed and running on your local system.

Step 1: Initializing Express App

As usual, create the package.json using npm init and install the following dependencies and dev dependencies.

npm install express mongoose
npm install --save-dev nodemon

(nodemon will auto reload the app, each time we make a change in our code)

Now it's time to setup our express app. To do this, let's create our app.js

const express = require('express');
const mongoose = require('mongoose');

// Create the app instance and listen on port 5000
const app = express();
app.listen(5000);

Now to run our app.js, let's modify our package.json .

"scripts": {
    "dev": "nodemon app.js"
  },

Finally, we can run the app by doing npm run dev on our terminal.

Step 2: Connect to your MongoDB database.

To make a connection to your MongoDB database, we need to use the connect method.

This is how you do it:

const express = require('express');
const mongoose = require('mongoose');

// Create the app instance and listen on port 5000
const app = express();
app.listen(5000);

// Connect to mongodb database using mongoose
const URL = "mongodb://127.0.0.1:27017/database";
mongoose.connect(URL, {useNewUrlParser: true, useUnifiedTopology: true});

The link "mongodb://127.0.0.1:27017/" is the link to our MongoDB service. I want to connect to the database named "database" within the service(It will create a new database if it doesn't exist).

Step 3: Create a Schema

Now that we have connected to a database, it's time to make a Schema. If you always get confused about the terms Collection, Document, Schema and etc., remember it like this.

Let's take a storage room for an example. Think of the storage room as the MongoDB service. Within the storage room, there are multiple boxes, all filled with multiple files. Each file contains a stack of papers.

Storage room -> Boxes -> Files -> Papers

MongoDB is just like that. Within MongoDB service, there are multiple databases. Inside each database, there are collections(similar to the boxes), which contains Documents(similar to the papers).

MongoDB Service -> Databases -> Collection -> Document

A "schema" is the blueprint, which we use to create a "model". Using that model, we can create a "Document". A "Collection" is simply a collection of Documents that are similar(made with the same model).

Our goal is to create a Schema and then use that Schema to create a model. Then we will be using that model to save our data to the database.

To create a schema,

const mySchema = new mongoose.Schema({
    name: String,
    email: String
});

// Or use the following method
const mySchema = new mongoose.Schema({
    name: {
        type: String
    },
    email: {
        type: String
    }
});

The benefit of using the second method is that we can define multiple properties for our data type.

You can find additional information about the different schema types here.

Now the final code should look like this:

const express = require('express');
const mongoose = require('mongoose');

// Create the app instance and listen on port 5000
const app = express();
app.listen(5000);

// Connect to mongodb database using mongoose
const URL = "mongodb://127.0.0.1:27017/database";
mongoose.connect(URL, {useNewUrlParser: true, useUnifiedTopology: true});

// Creating a Schema
const mySchema = new mongoose.Schema({
    name: String,
    email: String
});

Step 4: Static methods

Now that we have a blue print of how we want to structure our data in the database(the schema), we need a way to save the data using that schema.

There are different ways for doing this, but I'm going to be creating something called a static method to handle it.

mySchema.static('saveData', function(item){
    const documentObj = new this({name: item.name, email: item.email});
    return documentObj.save();
});

There are 3 ways to create a static method. You can find all of them here. Feel free to use whichever style that you prefer.

First call .static on our schema. It takes two arguments, a name for the method that you are creating and a function (You can't use an arrow function because it will prevent you from binding this keyword.)

Step 5: Creating a Model

To create the model using our schema,

const myModel = mongoose.model('myModel', mySchema);

This is how your final code should look like:

const express = require('express');
const mongoose = require('mongoose');

// Create the app instance and listen on port 5000
const app = express();
app.listen(5000);

// Connect to mongodb database using mongoose
const URL = "mongodb://127.0.0.1:27017/database";
mongoose.connect(URL, {useNewUrlParser: true, useUnifiedTopology: true});

// Creating a Schema
const mySchema = new mongoose.Schema({
    name: String,
    email: String
});

// Creating a static method to save data
mySchema.static('saveData', function(item){
    const documentObj = new this({name: item.name, email: item.email});
    return documentObj.save();
});

// Creating a model using "mySchema"
const myModel = mongoose.model('myModel', mySchema);

Now that we have our model, we can start saving data to our database.

Step 6: Creating and saving Documents

Now we need to create an async function, which will allow us to save data asynchronously, while making our code reusable.

async saveToDB(my_data){
    await myModel.saveData(my_data);
}

Since we are using an async function, we need to use await to save the document so that the operation completes before proceeding further.

Now when we want to save data, we will call the saveToDB function:

saveToDB({ name: "John Smith", email: "j_smith@gmail.com"});

Now the complete code should look like this:

const express = require('express');
const mongoose = require('mongoose');

// Create the app instance and listen on port 5000
const app = express();
app.listen(5000);

// Connect to mongodb database using mongoose
const URL = "mongodb://127.0.0.1:27017/database";
mongoose.connect(URL, {useNewUrlParser: true, useUnifiedTopology: true});

// Creating a Schema
const mySchema = new mongoose.Schema({
    name: String,
    email: String
});

// Creating a static method to save data
mySchema.static('saveData', function(item){
    const documentObj = new this({name: item.name, email: item.email});
    return documentObj.save();
});

// Creating a model using "mySchema"
const myModel = mongoose.model('myModel', mySchema);

// Save data asynchronously using "saveData" method
async saveToDB(my_data){
    await myModel.saveData(my_data);
}

// saving data to the database by calling the saveToDB function
saveToDB({ name: "John Smith", email: "j_smith@gmail.com"});

Step 7: Searching the database

After saving data, we may need to query the database too. For this, I'm going to create another static method which will return all the database entries. If you want to do any advance querying, check here to see other available options.

Here, I'm using .find(), which will return a array of all the database entries.

mySchema.static('findData', function(){
    return this.find();
});

We need to create this static method before creating the model, but after creating the Schema. So the code will look like this:

const express = require('express');
const mongoose = require('mongoose');

// Create the app instance and listen on port 5000
const app = express();
app.listen(5000);

// Connect to mongodb database using mongoose
const URL = "mongodb://127.0.0.1:27017/database";
mongoose.connect(URL, {useNewUrlParser: true, useUnifiedTopology: true});

// Creating a Schema
const mySchema = new mongoose.Schema({
    name: String,
    email: String
});

// Creating a static method to save data
mySchema.static('saveData', function(item){
    const documentObj = new this({name: item.name, email: item.email});
    return documentObj.save();
});

// Static method to find all db entries
mySchema.static('findData', function(){
    return this.find();
});

// Creating a model using "mySchema"
const myModel = mongoose.model('myModel', mySchema);

// Save data asynchronously using "saveData" method
async saveToDB(my_data){
    await myModel.saveData(my_data);
}

// saving data to the database by calling the saveToDB function
saveToDB({ name: "John Smith", email: "j_smith@gmail.com"});

Just like when we created the saveToDB function, we can use this method asynchronously.

//... rest of the code ...

async searchDB(){
    const db_data = await myModel.saveData(my_data);

    // perform operation on db_data

}

Now the complete code looks like this:

const express = require('express');
const mongoose = require('mongoose');

// Create the app instance and listen on port 5000
const app = express();
app.listen(5000);

// Connect to mongodb database using mongoose
const URL = "mongodb://127.0.0.1:27017/database";
mongoose.connect(URL, {useNewUrlParser: true, useUnifiedTopology: true});

// Creating a Schema
const mySchema = new mongoose.Schema({
    name: String,
    email: String
});

// Creating a static method to save data
mySchema.static('saveData', function(item){
    const documentObj = new this({name: item.name, email: item.email});
    return documentObj.save();
});

// Static method to find all db entries
mySchema.static('findData', function(){
    return this.find();
});

// Creating a model using "mySchema"
const myModel = mongoose.model('myModel', mySchema);

// Save data asynchronously using "saveData" method
async saveToDB(my_data){
    await myModel.saveData(my_data);
}
async searchDB(){
    const db_data = await myModel.saveData(my_data);

    // perform operation on db_data

}

// saving data to the database by calling the saveToDB function
saveToDB({ name: "John Smith", email: "j_smith@gmail.com"});

// call the searchDB function
searchDB();

Discussion

Now we can save and query our data to a database. As our application grows, the code needs to be split into modules to make it easier to maintain.

So, I'm gonna create a new file called 'model.js' and paste the code related to creating the model into it.

In the model.js, I need to require mongoose at the top and also export our myModel model at the end.

// model.js file

const mongoose = require('mongoose');

// Creating a Schema
const mySchema = new mongoose.Schema({
    name: String,
    email: String
});

// Creating a static method to save data
mySchema.static('saveData', function(item){
    const documentObj = new this({name: item.name, email: item.email});
    return documentObj.save();
});

// Static method to find all db entries
mySchema.static('findData', function(){
    return this.find();
});

// Creating a model using "mySchema"
const myModel = mongoose.model('myModel', mySchema);

module.exports = { myModel }

You maybe wondering, why we didn't add:

const URL = "mongodb://127.0.0.1:27017/database";
mongoose.connect(URL, {useNewUrlParser: true, useUnifiedTopology: true});

Remember that each database can have multiple collections? Right now we created a model which saves data to a collection named 'myModel' ( const myModel = mongoose.model('myModel', mySchema); ). But we can create a different model with using a different schema and save data to a different collection. So, in summary, we can use multiple models to save data.

Each time we want to save data to the database, we need to make a connection to the database. Instead, if we make the connection in our app.js and keep it open, then we can use other models to save data without reconnecting. That is why we're keeping those lines of code in the app.js.

Now all we need to do is require our models in the app.js:

// app.js file

const express = require('express');
const mongoose = require('mongoose');
const { myModel } = require('./model');

// Create the app instance and listen on port 5000
const app = express();
app.listen(5000);

// Connect to mongodb database using mongoose
const URL = "mongodb://127.0.0.1:27017/database";
mongoose.connect(URL, {useNewUrlParser: true, useUnifiedTopology: true});

// Save data asynchronously using "saveData" method
async saveToDB(my_data){
    await myModel.saveData(my_data);
}
async searchDB(){
    const db_data = await myModel.saveData(my_data);

    // perform operation on db_data

}

// saving data to the database by calling the saveToDB function
saveToDB({ name: "John Smith", email: "j_smith@gmail.com"});

// call the searchDB function
searchDB();

In conclusion, this method allows us to only import our models whenever we want to interact with the database. We don't need to have separate functions to save, delete and query data. This will help keep our code organized and look clean.

Finally

This is my first ever blog post, so it maybe a bit all over the place. So, if you have any questions or if anything was unclear, let me know. I will do my best to explain.

Also, I would really appreciate any feed you can give me so that I can improve my writing.