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