Begin with the End In Mind
- Initialize a directory
- Start express
- Create
New
Route - Create
Create
Route - Connect Express to Mongo
- Create Fruits Model
- Have Create Route Create data in MongoDB
- Create Index Route
- Have Index Route Render All Fruits
- Have Create Route redirect to Index After Fruit Creation
- Create Show Route
- Have Index Page Link to Show Route
- Create
Show.JSX
file
CRUD, MVC, REST, INDUCES and JSX: Remember where we are going
Model-View-Controller
Model–view–controller (MVC) is a software architectural pattern for implementing user interfaces on computers. It divides a given application into three interconnected parts. The division is done to separate internal representations of information from the way information is presented to, and accepted from, the user. The MVC design pattern decouples these significant components allowing for efficient code reuse and parallel development.
Advantages
Simultaneous development – multiple developers can work simultaneously on the model, controller, and views.
High cohesion
MVC enables logical grouping of related actions on a controller together. The views for a specific model are also grouped.
Low coupling
the MVC pattern ensures low coupling between models, views or controllers.
Ease of modification
because of the separation of responsibilities, future development or change is easier.
Multiple representations for a model
models can have various views.
Reminder of what we did to get here
Remember this how we Initialized a npm directory
- First we Created a directory for the app in
classwork
calledfruits
andcd
into it touch server.js
npm init -y
npm i express jsx-view-engine react react-dom dotenv
Review some express boilerplate
const express = require('express');
const app = express();
app.set('view engine', 'jsx');
app.engine('jsx', require('jsx-view-engine').createEngine());
// ...Other code
// ...More code
app.listen(3000, ()=>{
console.log('listening');
});
Review how we put together the New Route
mkdir views
touch views/New.jsx
- Create the view
const React = require('react');
class New extends React.Component {
render() {
return (
<div>
<h1>New Fruit page</h1>
<form action="/fruits" method="POST">
Name: <input type="text" name="name" /><br/>
Color: <input type="text" name="color" /><br/>
Is Ready To Eat: <input type="checkbox" name="readyToEat" /><br/>
<input type="submit" name="" value="Create Fruit"/>
</form>
</div>);
}
}
module.exports = New;
Render the view
app.get('/fruits/new', (req, res)=>{
res.render('fruits/New');
});
Review how we put together the Create Route
app.post('/fruits/', (req, res)=>{
res.send('received');
});
- Use body parser in server.js:
app.use(express.urlencoded({extended:true}));
Check to see if req.body works:
app.post('/fruits/', (req, res)=>{
res.send(req.body);
});
Format data properly
app.post('/fruits/', (req, res)=>{
if(req.body.readyToEat === 'on'){ //if checked, req.body.readyToEat is set to 'on'
req.body.readyToEat = true;
} else { //if not checked, req.body.readyToEat is undefined
req.body.readyToEat = false;
}
fruits.push(req.body);
res.redirect('/fruits')
});
Then we added vegetables
Now Lets connect to our MongoDB Database with Mongoose and MongoDB Atlas
- Mongoose is the go to when it comes to working with a MongoDB.
- We define Mongoose schemas, which are then compiled using the
mongoose.model
method into Models. - We use a Model to perform all CRUD for a given MongoDB collection.
Our MongoDB information is a secret so we need to set up Environment Variables
- Install
dotenv
node package - Update
.gitignore
to include .env (always do this before you commit anything in .env) - touch the
.env
file - lets add our connection string into the
.env
- update our
server.js
to add ourrequire('dotenv').config()
to the very top of the file - this places every kvp in our
.env
into a javascript object calledprocess.env
Create a cloud-based MongoDB database with Atlas
While developing an application that requires a MongoDB, you can only connect to your local MongoDB engine for so long. This is because the application, once deployed, will have to connect to a MongoDB engine accessible via the Internet. So we are going to use MongoDB Atlas from the beginning so that your application data always persists in the Cloud.
Some application hosting services we deploy our projects to are capable of supplying a MongoDB. However, delaying connecting to a hosted database until the time of deployment is not ideal...
It makes sense to set up and connect to a hosted MongoDB sooner, rather than later. Doing this will ensure that any data, users, etc., created will be there upon deployment.
In addition, it's advantageous to use a service to host MongoDB databases other than the deployment service, so that you can create databases anytime you want.
The most popular service for hosting MongoDB databases, not surprisingly, is MongoDB's own Atlas. ALSO NOTE: YOU WILL ONLY DO THIS ONCE !!!!! DON'T CREATE MULTIPLE CLUSTERS
Create an Atlas Account
First you will need to signup for a free account here:

Create a New Cluster
Once logged in, Atlas will request that you create a cluster. (click on build a New cluster, if you don't see create)
Atlas allows one free cluster per account.
A cluster can contain multiple MongoDB databases - which Atlas refers to as namespaces.
Be sure to select the Cloud Provider & Region nearest to you that shows a FREE TIER AVAILABLE:

Next, in the Cluster Tier section, select the M0 Sandbox
tier:

Finally, you can optionally change the name of the cluster, then click the Create Cluster
button:

It may take several minutes for Atlas to build your cluster.
Add a User for the Cluster
Each cluster must have a user created whose credentials will be provided in the database connection string when connecting to a database.
First click the Security tab:

Click the + ADD NEW USER
button, then enter a username, password, select the Read and write to any database option, then click the Add User
button also note password should be letters and number only no special characters no spaces no underscores:

Update the Whitelisted IPs
Atlas has a security feature that allows the databases to be accessed by whitelisted (approved) IP addresses only.
However, you must whitelist all IPs to ease development and deployment of your application, once you are ready to deploy you will restrict it to only your ip and the ip of your deployed server (It's not time to do that yet though)
While still in the Security tab, click IP Whitelist, then click the + ADD IP ADDRESS
button.
In the dialog, first click ALLOW ACCESS FROM ANYWHERE
then click the Confirm
button:

Obtain the Connection String
To obtain the connection string for your .env
file, first click the CONNECT
button:

Select the Connect Your Application option:

Next, ensure that the Node.js driver and latest version is selected. Then click the Copy
button to add the connection string to your clipboard:

Use the Connection String in Your App
You can now paste the connection string in the app's .env
file, assigning it to a MONGO_URI
environment variable:
MONGO_URI=mongodb+srv://sei:<THISISTHEPASSWORD___REMOVE___THE___CARATS>@sei-w0kys.azure.mongodb.net/<THISISTHEDATABASENAME___REMOVE___THE___CARATS>?retryWrites=true
You're almost done, but you need to update the connection string as follows:
- Replace
<password>
with the password of the database user you created earlier. - IMPORTANT The connection string by default connects to a namespace (database) named
test
(...mongodb.net/test?retryWrites=true...
). However, thetest
namespace must be updated to your preferred namespace (database) name. For example, "movies" (...mongodb.net/movies?retryWrites=true...
).
You're good to go!
Connecting with Mongoose
Here's the latest options to include to get rid of the deprecation warnings:
mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
});
Viewing & Editing Data
FYI, you can use the Atlas app to view and edit data by clicking on the COLLECTIONS
button.
Connect Express to Mongo
npm i mongoose
- Inside server.js:
const mongoose = require('mongoose');
//... and then farther down the file
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', ()=> {
console.log('connected to mongo');
});
Create Fruits Model
mkdir models
touch models/fruit.js
- Create the fruit schema
const mongoose = require('mongoose');
const fruitSchema = new mongoose.Schema({
name: { type: String, required: true },
color: { type: String, required: true },
readyToEat: Boolean
});
const Fruit = mongoose.model('Fruit', fruitSchema);
module.exports = Fruit;
Have Create Route Create data in MongoDB
Inside server.js:
const Fruit = require('./models/fruit.js');
//... and then farther down the file
app.post('/fruits/', (req, res)=>{
if(req.body.readyToEat === 'on'){ //if checked, req.body.readyToEat is set to 'on'
req.body.readyToEat = true;
} else { //if not checked, req.body.readyToEat is undefined
req.body.readyToEat = false;
}
Fruit.create(req.body, (error, createdFruit)=>{
res.send(createdFruit);
});
});
Review and Refactor Index Route
app.get('/fruits', (req, res)=>{
res.send('Index');
});
touch views/Index.jsx
const React = require('react');
class Index extends React.Component {
render() {
return <div><h1>Fruits index page</h1></div>;
}
}
module.exports = Index;
Render the jsx file
app.get('/fruits', (req, res)=>{
res.render('fruits/Index');
});
Have Index Route Render All Fruits
app.get('/fruits', (req, res)=>{
Fruit.find({}, (error, allFruits)=>{
res.render('fruits/Index', {
fruits: allFruits
});
});
});
Update the jsx file:
const React = require('react');
class Index extends React.Component {
render() {
return (
<div>
<h1>Fruits index page</h1>
<ul>
{
this.props.fruits.map((fruit, i) => {
return (
<li>
The { fruit.name } is { fruit.color }
{ fruit.readyToEat ? `It is ready to eat` : `It is not ready to eat` }
</li>
)
})
}
</ul>
</div> );
}
}
module.exports = Index;
Add a link to the new page:
<nav>
<a href="/fruits/new">Create a New Fruit</a>
</nav>
Have Create Route redirect to Index After Fruit Creation
Inside the create route
Fruit.create(req.body, (error, createdFruit)=>{
res.redirect('/fruits');
});
Create Show Route
app.get('/fruits/:id', (req, res)=>{
Fruit.findById(req.params.id, (err, foundFruit)=>{
res.send(foundFruit);
});
});
Have Index Page Link to Show Route
{
this.props.fruits.map((fruit, i) => {
return (
<li>
The <a href={`/fruits/${ fruit.id }`}> { fruit.name } </a> is { fruit.color }
{ fruit.readyToEat ? `It is ready to eat` : `It is not ready to eat` }
</li>
)
})
}
Create Show.jsx
touch views/Show.jsx
- Add JSX
const React = require('react');
class Show extends React.Component {
render(){
return (
<div>
<h1>Fruits show page</h1>
The { this.props.fruit.name } is { this.props.fruit.color }
{ this.props.fruit.readyToEat ? `It is ready to eat` : `It is not ready to eat` }
</div>
)
}
}
module.exports = Show;
Render the jsx
app.get('/fruits/:id', (req, res)=>{
Fruit.findById(req.params.id, (err, foundFruit)=>{
res.render('fruits/Show', {
fruit:foundFruit
});
});
});
Review Questions
❓ In your own words, describe the use case for Mongoose (what is it's purpose and when might you choose to use it?).
❓ A Mongoose _ is compiled into a Mongoose Model.
❓ We use a Mongoose _ to perform CRUD operations on a MongoDB..