🔖 [Nodejs] Using Express to connect MongoDB

2018 - 04 - 22
🔖 [Nodejs] Using Express to connect MongoDB
0. [Install Express] As we went through the basic http server from Nodejs in last post, we talked about a module that help to build a server quicker. Express is a handy and may be still the most popular module for Nodejs to build server these days. To use Express, we have to init npm (Node Package Manager which is bundled in Nodejs) first. Terminal:
$mkdir mynode
npm init --yes
this will create a file named package.json. Then we can install express in same folder via npm: Terminal:
$npm i express
Create an app.js file in the same folder: app.js
const express = require('express');
const app = express();
To avoid rebooting the server manually, install the package nodemon globally(to call it everywhere):
$npm i -g nodemon
Hence, instead of running the server by calling "node app.js", now we call
$nodemon app
and it will reload whenever there is amendment made.
1. [Get function] Express has 4 main functions, they are
  • GET
  • POST
  • PUT (similar to UPDATE)
  • DELETE
First, we use the GET method. app.js
const express = require('express');
const app = express();

app.get('/', (req, res)=>{
	res.send('Hello!');
});

const port = process.env.PORT || 8000;
app.listen(port, ()=>console.log(`Listening on port ${port}...`));
Now open Chrome and head to localhost:8000, you'll see the word "Hello" on left top corner. To use a html page instead of just a sentence (of coz!), we use res.sendFile instead. Build a dummy html page and save it at ../views/index.html, then in the app.js:
app.get('/', (req, res)=>{
	res.sendFile(__dirname+'/views/', 'index.html');
});
Since we defined the PORT by using environment variables, we can use other port instead of 8000 by declaring at terminal: Terminal:
$export PORT=3000

2. [Route & Query Parameters] For get requests with a key, we do it in a similar way as that Django framework, i.e. using the urlpatterns / route parameters - req.params:
app.get('/:abc', (req, res)=>{
	res.send(req.params.abc);
});
The key value that requested, for example "something" will be saved in req.paramsJSON format, i.e. {abc: something}. If we open the browser and enter localhost:8000/key, it'll show the key that we requested "key" on the page. If we have a list of posts such as:
posts = [
	{id:1, title:'Day1'}, 
	{id:2, title:'Day2'}, 
	{id:3, title:'Day3'}
]
We can return a certain post by:
app.get('/post/:id', (req, res)=>{
	let target = post.find(p=>p.id === parseInt(req.params.id));
	if(target){
		res.send(target)
	} else {
		res.send('No Such Post :(')
	};
});
Whenever we have some extra query such as ordering or sorting the query, we can use query parameters - req.query. For example, url requests like localhost:8000/apple?order=asc. Similar to route parameters, query parameters are also stored in JSON format. To recall the query we have made, we can use req.query:
app.get('/:abc', (req, res)=>{
	res.send(req.query);
});

3. [Post function] To post something, we need a form. Make a form in views/index.html as follow:
<form method='POST' action='./newpost'>
	<input type='text' name='title'>
	<button type='submit'>Submit</button>
</form>
Then we need a package named body-parser for posting, Terminal:
$npm i body-parser
So now we can add this body-parser as middleware of Express and read the posted data in request body: app.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: true})); //false=only string or array as value, true=anything

app.post('/newpost', (req, res)=>{
	res.send(req.body)
});
Now, when you submit the form on browser, the data is saved and passed to req.body, and the page will be directed to localhost:8000/newpost. From there, we can see the submitted data in JSON format.
4. [MongoDB] To use MongoDB as database, we need MongoClient to handle, Terminal:
$npm i mongodb
So we can add it to our app.js:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: true}));
const MongoClient = require('mongodb').MongoClient;
Then we need to register an online MongoDB at mLab,
  • Register an account
  • Create a free database using sandbox plan
  • Create a database user for using it
  • Copy the database link
Next, we are going to connect to the mLab mongoDB using MongoClient: app.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: true}));
const MongoClient = require('mongodb').MongoClient;

MongoClient.connect('mongodb://<username>:<password>@ds257808.mlab.com:57808/database_name', (err, client)=>{
	if(err){console.log(err)};
	let db = client.db('database_name');
	app.listen(8000, ()=>console.log('Listening to port 8000...'))
});
Noted that we moved the port listener into MongoClient since we don't want to run the server if the connection to database is lost. Instead of pushing to a local array named posts, we want to push those submitted data to database, we are going to alter the post part in Step3: app.js
app.post('/newpost', (req, res)=>{
	db.collection('posts').save(req.body, (err, result)=>{
		console.log('Saved to database!');
		res.redirect('/')
	});
});
Now whenever you post from the form on index.html, the form action will direct you to URL localhost:8000/newpost to run the posting and redirect you back to root page. Meanwhile, Nodejs will save your submitted data as req.body in JSON format and push it to mongoDB on mLab under collection - posts. From mLab, we can see pushed data in JSON format:
5. [dotenv] This is important! Since we need to include the username and password for accessing database in MongoClient.connect, it is better to save such confidential data in .env file. Install the package dotenv:
$npm i dotenv
Create a .env file and copy the whole link to database into it, for example:
DB_SETTING=mongodb://kavie:<123456>@ds257808.mlab.com:57808/mydatabase
DB_NAME=mydatabase
Then add this line to the very beginning of app.js:
require('dotenv').config();
and change the command for MongoClient.connect as follow:
MongoClient.connect(DB_SETTING, (err, client)=>{
	if(err){console.log(err)};
	let db = client.db(DB_NAME);
	app.listen(8000, ()=>console.log('Listening to port 8000...'))
});

6. [Retrieving data from mongoDB] To get data back from mongoDB, we can use app.get and db. app.js:
app.get('/allpost', (req, res)=>{
	db.collection('posts').find({}).toArray((err, result)=>{
		if(err){
			console.log(err)
		} else {
			res.send(result)
		}
	})
});
this will show the data in JSON format. Alternatively, we can manipulate and present the data in templates using a package named ejs (Embedded JavaScript templates). Install ejs from with npm:
$npm i ejs
Add this package to Express: app.js
app.set('view engine', 'ejs');
All templates are in *.ejs extensions and put under /views/ folder. Let's build an index.ejs for rendering:
<html>
	<head>
		<title>Node Test</title>
	</head>
	<body>
		<% result.forEach(r=>{%>
		<div class='row'>
			<div><%= r.title %>: <%= r.date %></div>
		</div>
		<%});%>
		<div class='row'>
			<form method='POST' action='./newpost'>
				<label for='title'>Title</label><input type='text' name='title'>
				<label for='date'>Date</label><input type='hidden' name='date' id='date'>
				<button type='submit'>Submit</button>
			</form>
		</div>
	</body>
	<script>
		let now = new Date();
		let d = now.getDate();
		let m = now.getMonth();
		let y = now.getFullYear();
		document.querySelector('#date').value = `${d}-${m}-${y}`;
	</script>
</html>
As mentioned, this file should be put under ./views/. Note that we have JavaScript on the page:
  • <% and %> are used for running JavaScript
  • <%= and %> are used for displaying the output
Next step, we have to update the get method in app.js:
//------------------------------------------------------
//dotenv
require('dotenv').config();
//Express
const express = require('express');
const app = express();
//body-parser
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: true}));
//mongoDB
const MongoClient = require('mongodb').MongoClient;
let db;
//ejs
app.set('view engine', 'ejs');
//------------------------------------------------------

//Connect to mongoDB
MongoClient.connect(process.env.DB_SETTING, (err, client)=>{
	db = client.db(process.env.DB_NAME);
	//port
	const port = process.env.PORT || 8000;
	app.listen(port, ()=>console.log(`Listening on port ${port}...`));
});


//Get
app.get('/', (req, res)=>{
	db.collection('posts').find({}).toArray((err, result)=>{
		if(err){
			console.log(err)
		} else {
			res.render('index.ejs', {result: result})
		}
	})
});

//Post
app.post('/newpost', (req, res)=>{
	db.collection('posts').save(req.body, (err, result)=>{
		if(err){console.log(err)};
		//res.send(req.body)
		res.redirect('/')
	});
});
Since we have ejs as view engine, it provides rendering for responses res.render. The result of db.collection is assigned to parameter result to and rendered in index.ejs.

Comments

There is no comment yet

New Comment

Please Login to comment