DEV Community

Cover image for NodeJS + Express part 6: MongoDB database
Eric The Coder
Eric The Coder

Posted on

NodeJS + Express part 6: MongoDB database

Here is a series of articles that will allow you to create backend applications with NodeJS + Express.

This series is the continuation of my series on the basics of NodeJS. If you don't have basic knowledge of NodeJS read this series first: Introduction to NodeJS

Node.js is today a must, so it is essential for a developer to master it.

So I will publish a new article about every two days and little by little you will learn everything there is to know about Node.js + Espress

To not miss anything follow me on twitter: https://twitter.com/EricTheCoder_


MongoDB Database

In this section we will learn how to manipulate a MongoDB database from our API.

You probably know that there are several types of databases such as SQL databases and NoSQL databases.

The purpose of this article is not to explain in detail what a database is and how it works internally. So a minimum of database knowledge is required.

Today we are going to use MongoDB which is a NoSQL database

NoSQL databases contain collections that contain documents. For example a database could have the User collection and several documents which would each contain the information of a user such as for example: no, last name, first name, etc.

If you have experience with SQL databases, we could simplify this by saying that collections are tables and documents are rows and columns of tables.

MongoDB installation

MongoDB can be installed on your local machine or be used as a cloud database version.

In this tutorial we will create a MongoDB database from their cloud. https://www.mongodb.com/atlas

The service is free and does not require a credit card.

To have access to the MongoDB cloud and then be able to create your own database, go to https://www.mongodb.com/atlas and click on the "Try Free" button.

Choose the Atlas service, complete the questionnaire and click "Get started free"

Once your account is created, go to the control panel, you should see something like this.
Image description

Click on "Build a Database", then choose the "Free Shared" option and click on "Create". Then keep the default options except the last option which is "Cluster Name" and change the name to "NodeExpress". Finally click on "Create Cluster"

Create a database

Your MongoDB account is created and activated we will now create our database and our first collection

With your cluster now created, you should see something like this
Image description

To create a database and a collection. Click on "Browse Collection", then on "Add My Own Data". Finally enter the name of the database and the name of the collection and click on "Create"

Image description

Ready to code

To sum up, we created a MongoDB cloud account, created a free Cluster and created our first "Demo" database and finally our first "Products" collection.

Now we are ready to code our API and manipulate our database

Creation of the NodeJS project

We are now going to create our NodeJS project, I will give here the starting code (which comes from the previous articles).

Create a folder

$ mkdir demo-express-mongo
$ cd demo-express-mongo
Enter fullscreen mode Exit fullscreen mode

Then install the ExpressJS package and nodemon

$ npm install express
$ npm nodemon
Enter fullscreen mode Exit fullscreen mode

Note that as specified in the section on NodeJS, the nodemon package allows you to reload the server each time our code is modified.

In order not to repeat the concepts that we covered in the previous articles, we will start with the same code that we had at the end of the last article.

Create a controllers folder and create a products.js file with the following code

const products = require('../data.js')

const getProducts = ((req, res) => {
    res.json(products)
})

const getProduct = ((req, res) => {
    const id = Number(req.params.productID)
    const product = products.find(product => product.id === id)

        if (!product) {
        return res.status(404).send('Product not found')
    }
    res.json(product)
})

const createProduct = ((req, res) => {
    const newProduct = {
        id: products.length + 1,
        name: req.body.name,
        price: req.body.price
    }
    products.push(newProduct)
    res.status(201).json(newProduct)
})

const updateProduct = ((req, res) => {
    const id = Number(req.params.productID)
    const index = products.findIndex(product => product.id === id)
    const updatedProduct = {
        id: products[index].id,
        name: req.body.name,
        price: req.body.price
    }

    products[index] = updatedProduct
    res.status(200).json('Product updated')
})

const deleteProduct = ((req, res) => {
    const id = Number(req.params.productID)
    const index = products.findIndex(product => product.id === id)
    products.splice(index,1)
    res.status(200).json('Product deleted')
})

module.exports = {
    getProducts,
    getProduct,
    createProduct,
    updateProduct,
    deleteProduct
}
Enter fullscreen mode Exit fullscreen mode

Then, create a "routes" folder and create the products.js file

const express = require('express')
const router = express.Router()

const  { 
    getProducts,
    getProduct,
    createProduct,
    updateProduct,
    deleteProduct 
} = require('../controllers/products.js')

router.get('/', getProducts)

router.get('/:productID', getProduct)

router.post('/', createProduct) 

router.put('/:productID', updateProduct) 

router.delete('/:productID', deleteProduct)

module.exports = router

Enter fullscreen mode Exit fullscreen mode

Finally, create an app.js file with the following code

const express = require('express')
const app = express()
const products_routes = require('./routes/products.js')

app.listen(5000, () => {
    console.log('server is listening on port 5000')
})

app.use(express.json())
app.use('/api/products', products_routes)
Enter fullscreen mode Exit fullscreen mode

So far nothing new, we are ready to continue this code by adding our MongoDB database

fichier .env

To connect to our MongoDB database we need the connection URL. MongoDB will provide us with this URL. The thing is, for obvious security reasons, we can't use this login URL directly in our code.

The connection URL must be placed in a file that will be out of reach of users during deployment.

To do this we will therefore create a file that will contain our connection URL. By convention this file named ".env" (dot env)

You can create this file at the root of the project and include the MongoDB connection URL

// .env 
MONGO_URI = 'mongodb+srv://<username>:<password>@nodeexpress.my1j7.mongodb.net/myFirstDatabase?retryWrites=true&w=majority'
Enter fullscreen mode Exit fullscreen mode

To get your MongoDB login URL. Connect to your MongoDB cloud account and from the "Databases" menu click on "Connect", then choose the "Connect you application" option
Image description

MongoDB will show you your connection string, copy it and paste it into your .env file

In the connection string, replace and with your username and password MongoDB cloud user and also replace "myFirstDatabase" with the name of your database (ie "demo")

Communicating with MongoDB from NodeJS

There are several ways to communicate with your MongoDB database. For this project I decided to use the NodeJS package named "mongoose"

This packages makes it easy to link MongoDB and your API.

ODM

mongoose is an ODM (Object Document Mapping) which means that mongoose allows you to create an object (called a model) to represent and manipulate each of our collections.

This object (model) will contain several pre-defined functions that will allow you to easily handle the collection associated with this object.

Once the model is created, no need to manipulate the database, just use the methods of the model object and it will take care of communicating to the database. Suddenly, this pattern significantly increases the ease of handling the database.

Here is a quick example to visualize the concept

const products = await Product.find({})
Enter fullscreen mode Exit fullscreen mode

In this code, the "Product" object / model uses the "find" method in order to read all the documents in the collection. The documents retrieved are sent to the "products" variable.

Creation of a mongoose model

We are now going to create a "Product" object / model

The first step is to install the mongoose package

npm install mongoose
npm install dotenv
Enter fullscreen mode Exit fullscreen mode

While we are there we will also install the dotenv package. This package allows you to read the ".env" config file that we created earlier and load its variables into the current process.

Once the package is used, we can create our first mongoose model.

Create a "models" folder and create the Product.js file

const mongoose = require('mongoose')

const ProductSchema = new mongoose.Schema({
    name:String,
    price: Float,
})

const Product = mongoose.model('Product', ProductSchema)

module.exports = Product
Enter fullscreen mode Exit fullscreen mode

Mongoose models are created from the diagrams.

The diagram is used to define the structure of a document. (Kind of like the columns of a table in an SQL database).

In the last example we define the Product schema which will be the structure of the documents of the Products collection

The penultimate line allows you to create the Product model from the diagram

const Product = mongoose.model('Product', ProductSchema)
Enter fullscreen mode Exit fullscreen mode

Connection to the database

Now that we have a mongoose model to work with, we must now establish the connection between mongoose and our MongoDB database.

Modify the app.js file to include the database connection code.

const express = require('express')
const mongoose = require('mongoose')
const app = express()
const products = require('./data.js')
const products_routes = require('./routes/products.js')

require('dotenv').config()

mongoose.connect(process.env.MONGO_URI)
    .then((result) => app.listen(5000))
    .catch((err) => console.log(Error))

app.use(express.json())
app.use('/api/products', products_routes)
Enter fullscreen mode Exit fullscreen mode

Let's go back to the code with some explanations:

Send the contents of the .env file to the process.env object

require('dotenv').config()
Enter fullscreen mode Exit fullscreen mode

Use the MONGO_URL to create a connection with your database

mongoose.connect(process.env.MONGO_URI)
Enter fullscreen mode Exit fullscreen mode

If the connection is successful then start the NodeJS server otherwise display the error.

mongoose.connect(process.env.MONGO_URI)
    .then((result) => app.listen(5000))
    .catch((err) => console.log(Error))
Enter fullscreen mode Exit fullscreen mode

CRUD API

Now that we have our connection to MongoDB, we can modify our "products" controller file (/controllers/products.js) and add the Product model methods to it.

In fact the operation of these methods is so simple and explicit that we do not need to explain them.

const Product = require('../models/Product.js')

const getProducts = ((req, res) => {
    Product.find({})
        .then(result => res.status(200).json({ result }))
        .catch(error => res.status(500).json({msg: error}))
})

const getProduct = ((req, res) => {
    Product.findOne({ _id: req.params.productID })
        .then(result => res.status(200).json({ result }))
        .catch(() => res.status(404).json({msg: 'Product not found'}))
})

const createProduct = ((req, res) => {
    Product.create(req.body)
        .then(result => res.status(200).json({ result }))
        .catch((error) => res.status(500).json({msg:  error }))
})

const updateProduct = ((req, res) => {
    Product.findOneAndUpdate({ _id: req.params.productID }, req.body, { new: true, runValidators: true })
        .then(result => res.status(200).json({ result }))
        .catch((error) => res.status(404).json({msg: 'Product not found' }))
})

const deleteProduct = ((req, res) => {
    Product.findOneAndDelete({ _id: req.params.productID })
        .then(result => res.status(200).json({ result }))
        .catch((error) => res.status(404).json({msg: 'Product not found' }))
})

module.exports = {
    getProducts,
    getProduct,
    createProduct,
    updateProduct,
    deleteProduct
}
Enter fullscreen mode Exit fullscreen mode

However, if you want to know in detail how these methods work and the other methods available, see the mongoose documentation here: https://mongoosejs.com/docs/models.html

Test your API

You can now launch the Node.JS server and test the API

$ npx nodemon app.js
Enter fullscreen mode Exit fullscreen mode

The server will be launched on port 5000 accessible to localhost: 5000

Using software like Postman, you can now test your API with the following queries:

GET localhost:5000/api/products

GET localhost:5000/api/product/<id>

POST localhost:5000/api/products 

PATCH localhost:5000/api/products/<id> 

DELETE localhost:5000/api/products/<id>
Enter fullscreen mode Exit fullscreen mode

Note that for POST and PATH actions, you must send them with content in the body section of your request. Here is an example of content in JSON:

{
    "name": "iPhone12",
    "price": 899
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

That's all for today, follow me on twitter: https://twitter.com/EricTheCoder_ to be notified of the publication of the next article (within two days).

Discussion (0)