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}`) })