CRUD – READ
In Express, we handle a GET request with the get method:
app.get(endpoint, callback)
endpoint is the requested endpoint. It’s the value that comes after your domain name. Here are some examples:
- When you visit localhost:3000, you’re actually visiting localhost:3000/. In this case, browsers requested for /.
- You’re reading this article on https://zellwk.com/blog/crud-express-mongodb/. The domain name is zellwk.com. The requested endpoint is anything that comes after zellwk.com (which is /blog/crud-express-mongodb).
callback tells the server what to do when the requested endpoint matches the endpoint stated. It takes two arguments: A request object and a response object.
Set up HTML site
To do this, we use the sendFile method that’s provided by the res object
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html')
// Note: __dirname is directory current directory you're in. Try logging it and see what you get!
})
Nodemon
Nodemon restarts the server automatically when you save a file that’s used by the server.js. We can install Nodemon with the following command:
$ npm install nodemon --save-dev
Nodemod behaves like Node. So you can run nodemon server.js and you’d expect to see the same thing. Unfortunately, this only works if you’ve installed nodemon globally with the -g flag (and we didn’t do this).
We have other ways to run Nodemon. For example, you can execute Nodemon directly from the node_modules folder. This is super unweildy, but it works:
./node_modules/.bin/nodemon server.js
We can make things simpler by adding script key in the package.json file. This lets us run nodemon server.js without the ./node_modules… preamble.
{
// ...
"scripts": {
"dev": "nodemon server.js"
}
// ...
}
Now, you can run npm run dev to trigger nodemon server.js.
CRUD – CREATE
To send a POST request through a
Next, we’ll use res.render to render this index.ejs file.
app.get(‘/’, (req, res) => {
db.collection(‘quotes’).find().toArray()
.then(/ … /)
.catch(/ … /)
res.render(‘index.ejs’, {})
})
Let’s put the quotes into index.ejs. To do this, we need to pass the quotes into the render method.
app.get(‘/’, (req, res) => {
db.collection(‘quotes’).find().toArray()
.then(results => {
res.render(‘index.ejs’, { quotes: results })
})
.catch(/ … /)
})
In index.ejs, we can use place variables between <%= and %> tags. Let’s try putting quotes into the HTML:
…
<%= quotes %>
We see lots of [object Object] because each quote inside results is a JavaScript object. ejs cannot convert that object into HTML automatically.
We need to loop through the quotes. We can do this with a for loop. In EJS, we write a for loop like how we write a JavaScript for loop. The only difference is we need to put the for loop statements between <% and %>.
Quotes
-
<%= quotes[i].name %>:
<%= quotes[i].quote %>
<% for(var i = 0; i < quotes.length; i++) {%>
<% } %>
#### CRUD - UPDATE
We use the UPDATE operation when we want to change something. It can be triggered with a PUT request. Like POST, PUT can be triggered either through JavaScript or through a < form > element.
we need to add a button into the index.ejs file:
Darth Vadar invades!
Replace first Yoda’s quote with a quote written by Darth Vadar
We will also create an external JavaScript file to execute a PUT request. According to Express conventions, this JavaScript is kept in a folder called public
$ mkdir public
$ touch public/main.js
Then, we have to tell Express to make this public folder accessible to the public by using a built-in middleware called express.static
app.use(express.static(‘public’))
We now can add the main.js file to the index.ejs file:
We will send a PUT request when the button gets clicked. This means we need to listen to a click event.
Next, we’re going to send the PUT request when the button is clicked:
// main.js
const update = document.querySelector(‘#update-button’)
update.addEventListener(‘click’, _ => {
// Send PUT Request here
})
#### Sending a PUT Request
The easiest way to trigger a PUT request in modern browsers is to use the Fetch API.
Fetch has the following syntax:
fetch(endpoint, options)
In this case, let’s say we want to send the request to /quotes. We’ll set endpoint to /quotes.
update.addEventListener(‘click’, _ => {
fetch(‘/quotes’, {/ … /})
})
We need to send a PUT request this time. We can do this by setting Fetch’s method to put.
update.addEventListener(‘click’, _ => {
fetch(‘/quotes’, {
method: ‘put’
})
})
We need to tell the server we’re sending JSON data by setting the Content-Type headers to application/json.
update.addEventListener(‘click’, _ => {
fetch(‘/quotes’, {
method: ‘put’,
headers: { ‘Content-Type’: ‘application/json’ },
})
})
Next, we need to convert the data we send into JSON. We can do this with JSON.stringify. This data is passed via the body property.
update.addEventListener(‘click’, _ => {
fetch(‘/quotes’, {
method: ‘put’,
headers: { ‘Content-Type’: ‘application/json’ },
body: JSON.stringify({
name: ‘Darth Vadar’,
quote: ‘I find your lack of faith disturbing.’
})
})
})
#### Accepting the PUT request
Our server doesn’t accept JSON data yet. We can teach it to read JSON by adding the body-parser's json middleware.
app.use(bodyParser.json())
Next, we can handle the PUT request with a put method. You should be able to see the values we send from the fetch request.
app.put(‘/quotes’, (req, res) => {
console.log(req.body)
})
#### Changing Yoda’s quote
MongoDB Collections come with a method called findOneAndUpdate. This method lets us find and change one item in the database. It has the following syntax:
quotesCollection.findOneAndUpdate(
query,
update,
options
)
.then(result => {/ … /})
.catch(error => console.error(error))
query lets us filter the collection with key-value pairs. If we want to filter quotes to those written by Yoda, we can set { name: 'Yoda' } as the query.
quotesCollection.findOneAndUpdate(
{ name: ‘Yoda’ },
update,
options
)
.then(result => {/ … /})
.catch(error => console.error(error))
update, tells MongoDB what to change. It uses MongoDB’s update operators like $set, $inc and $push.
We will use the $set operator since we’re changing Yoda’s quotes into Darth Vadar’s quotes:
quotesCollection.findOneAndUpdate(
{ name: 'Yoda' },
{
$set: {
name: req.body.name,
quote: req.body.quote
}
},
options
)
.then(result => {/ … /})
.catch(error => console.error(error))
“`
options tells MongoDB to define additional options for this update request.
In this case, it’s possible that no Yoda quotes exist in the database. We can force MongoDB to create a new Darth Vadar quote if no Yoda quotes exist. We do this by setting upsert to true. upsert means: Insert a document if no documents can be updated.
quotesCollection.findOneAndUpdate(
{ name: 'Yoda' },
{
$set: {
name: req.body.name,
quote: req.body.quote
}
},
{
upsert: true
}
)
.then(result => {/* ... */})
.catch(error => console.error(error))
Finally, let’s log the result into the command line.
app.put('/quotes', (req, res) => {
quotesCollection.findOneAndUpdate(/* ... */)
.then(result => {
console.log(result)
})
.catch(error => console.error(error))
}
Finally, we need to respond to the JavaScript that sent the PUT request. In this case, we’ll simply send the success message.
app.put('/quotes', (req, res) => {
quotesCollection.findOneAndUpdate(/* ... */)
.then(result => {
res.json('Success')
})
.catch(error => console.error(error))
}
Next, we can handle the response from the server via a then object. (We do this because fetch returns a promise). However, Fetch is slightly different from most promises. You need to use another then object to get the response from the server.
fetch({ /* request */ })
.then(res => {
if (res.ok) return res.json()
})
.then(response => {
console.log(response)
})
CRUD – DELETE
The DELETE operation can be triggered through a DELETE request. It’s similar to the UPDATE request so this should be simple if you understand what we’ve done above.
First, we need to add a delete button to index.ejs.
<div>
<h2>Remove Darth Vadar!</h2>
<p>
Delete one Darth Vadar's quote. Does nothing if there are no more Darth
Vadar's quote
</p>
<button id="delete-button">Delete Darth Vadar's quote</button>
</div>
Then, we’ll trigger a DELETE request through Fetch when a user clicks the delete button.
const deleteButton = document.querySelector('#delete-button')
deleteButton.addEventListener('click', _ => {
fetch('/quotes', {
method: 'delete',
})
})
deleteButton.addEventListener('click', _ => {
fetch(/* ... */, {
method: 'delete',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'Darth Vadar'
})
})
.then(res => {
if (res.ok) return res.json()
})
.then(data => {
window.location.reload()
})
})
We can then handle the event on our server side with the delete method:
app.delete('/quotes', (req, res) => {
// Handle delete event here
})
Deleting a document from MongoDB
MongoDB Collections has a method called deleteOne. It lets us remove a document from the database. It takes in two parameters: query and options.
quotesCollection.remove(
query,
options
)
.then(result => {/* ... */})
.catch(error => console.error(error))
```
app.delete(‘/quotes’, (req, res) => {
quotesCollection.deleteOne(
{ name: req.body.name }
)
.then(result => {
res.json(Deleted Darth Vadar's quote
)
})
.catch(error => console.error(error))
})
#### What if there are no more Darth Vadar quotes?
If there are no more Darth Vadar quotes, result.deletedCount will be 0. We can send a message that says tells the browser that there are no more Darth Vadar quotes to delete.
app.delete(‘/quotes’, (req, res) => {
quotesCollection.deleteOne(/ … /)
.then(result => {
if (result.deletedCount === 0) {
return res.json(‘No quote to delete’)
}
res.json(Deleted Darth Vadar's quote
)
})
.catch(error => console.error(error))
})
[ORIGINAL ARTICLE FROM ZELL'S BLOG, A BIG THANKS FOR HELP!] (https://zellwk.com/blog/crud-express-mongodb/)