Week 11

Database

So far, we've been saving data on the back-end server, which is convenient but has major drawbacks. Most importantly, the data is lost when the server restarts.

To solve this, we need external storage with its own lifecycle—i.e., a database.

There are many types of databases, including MySQL, PostgreSQL, and Oracle. In this course, we'll use MongoDB, a document-oriented database. The advantage of MongoDB is that its documents are JSON-based, which we're already familiar with. We'll run MongoDB in a Docker container.

Run MongoDB

Run the following command to start MongoDB in a Docker container:

docker run --rm --name my-mongo -p 27017:27017 mongo

This will run an instance of the database on your system on port 27017.

We can get to the container with the following command:

docker exec -it my-mongo mongosh

This will use mongosh which is the MongoDB Shell.

Test Commands

show dbs # to list databases
use contacts # to switch to the 'contacts' database. if not there, it will create one first
show collections # to list collections (tables)
db.createCollection("contacts") # to create a 'contacts' collection
db.contacts.insertOne({name: "Alice"}) # to insert a record to the collection
db.contacts.find() # to list records in the collection
db.contacts.findOne({name: "Alice"}) # to get the record w/ name 'Alice'
db.contacts.updateOne({name: "Alice"}, {$set: {name: "Taylor"}}) # to update the record w/ name 'Alice'
db.contacts.deleteOne({name: "Taylor"}) # to delete record w/ name 'Taylor'
db.contacts.drop() # to delete the collection 'contacts'

Use MongoDB with Express.js

To use MongoDB with Express.js, we need to first install the mongodb package using npm:

npm install mongodb

We then need to import the package and connect to our database and select our collection:

const { MongoClient, ObjectId } = require("mongodb");
const mongoURI = "mongodb://localhost:27017";
const dbName = "contacts";
let db;
let collection;

MongoClient.connect(mongoURI)
    .then(client => {
        db = client.db(dbName);
        collection = db.collection("contacts")
        console.log("connected to MongoDB");
    })
    .catch(err => console.error("connection error:", err));

The next step would be to use our collection to interact with the database.

collection.insertOne(req.body) // to create record
collection.find().toArray() // to list all records in the collection
collection.findOne({ _id: new ObjectId(req.params.id) }) // to get a specific record
collection.updateOne({ _id: new ObjectId(req.params.id) }, { $set: req.body }) // to update a record
collection.deleteOne({ _id: new ObjectId(req.params.id) }) // to delete a record

Note that all these operations are async, so we need a await on them.

What We're Building

We're building the same Phone Book app but with a MongoDB database.

Backend code:

const express = require('express')
const { MongoClient, ObjectId } = require("mongodb");
const app = express()
const cors = require('cors')
const port = 3000
const mongoURI = "mongodb://localhost:27017";
const dbName = "contacts";
let db;
let collection;

MongoClient.connect(mongoURI)
    .then(client => {
        db = client.db(dbName);
        collection = db.collection("contacts")
        console.log("connected to MongoDB");
    })
    .catch(err => console.error("connection error:", err));

app.use(cors())
app.use(express.json());

app.get('/contacts', async (req, res) => {
    if (req.query.id) {
        const id = req.query.id
        const result = await collection.findOne({ _id: new ObjectId(id) })
        res.json(result)
    } else {
        const result = await collection.find().toArray()
        res.json(result)
    }
})

app.post('/contacts', async (req, res) => {
    const result = await collection.insertOne(req.body)
    res.json(result)
})

app.put('/contacts', async (req, res) => {
    const result = await collection.updateOne({ _id: new ObjectId(req.query.id) }, { $set: req.body })
    res.json(result)
})

app.delete('/contacts', async (req, res) => {
    const result = await collection.deleteOne({ _id: new ObjectId(req.query.id) })
    res.send(result)
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})