Upload and Store Images in MySQL using Node.Js, Express, Express-FileUpload & EJS Layouts
In this article, we will explore the Express-FileUpload NPM package by creating a super simple user profile card and integrate our card with a MySQL database to retain the record.
What you need:
To complete this project you will need a MySQL Database & Node installed. I usually use XAMPP for local development, but you can use whatever you wish as long as the database is MySQL of course.
Create a new project
To create a new project all you have to do is to create a new project folder, let’s call it “upload-files” and then run the following command below in Command line or PowerShell. Make sure that you CD to your project directory. To initialise a new project simply put the following command:
npm init
This will initialise a new project for you and it’s going to ask you a few questions about your project. The most important one is to give your package a name and then you can just keep pressing enter until the installation is over.
This will create a new package.json file for you.
Dependencies Installation
There are a few dependencies that we need to install to get started. Here is the list:
[x] express [x] express-ejs-layouts [x] mysql
Let’s do that by opening the terminal / powershell and install the dependencies by typing the following command:
npm i express express-ejs-layouts express-fileupload mysql
Now let’s install Nodemon which will help us restart the server every time we make a change. Note that Nodemon is a development dependency so we have to install it by adding the –save-dev flag.
npm i --save-dev nodemon
Your packages.json file should look similar to this:
{ "name": "nodejs-user-profile", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon app.js" }, "author": "", "license": "ISC", "dependencies": { "ejs": "^3.1.6", "express": "^4.17.1", "express-ejs-layouts": "^2.5.0", "express-fileupload": "^1.2.1", "mysql": "^2.18.1" }, "devDependencies": { "nodemon": "^2.0.7" } }
Project Structure
Let’s create the following folders and files, leaving node_modules, readme.md, package-lock and package-json as that should have been automatically generated by now.
You can structure your project the way you like. I am just going to keep it simple and add everything into our app.js file
📂 node_modules 📂 public 📂 css 📜 main.css 📜 main.scss 📂 img 🖼 default.jpg 📂 upload 📂 views 📂 layouts 📜 main.ejs 📜 index.ejs 📜 README.md ⚓ .env 🌍 app.js 📜 package-lock.json 📜 package-json
Let’s create our app.js file and each block of code will be explained with comments.
const express = require('express'); const expressLayouts = require('express-ejs-layouts'); const fileUpload = require('express-fileupload'); const mysql = require('mysql'); const app = express(); const port = process.env.PORT || 5000; // default option app.use(fileUpload()); // Static Files app.use(express.static('public')); app.use(express.static('upload')); // Templating engine app.use(expressLayouts); app.set('layout', './layouts/main'); app.set('view engine', 'ejs'); // Templating Engine // Connection Pool var connection = mysql.createConnection({ host: 'localhost', user: 'root', password: 'password', database: 'userprofile' }); // Our GET router for the homepage and a simple SELECT MySQL Query // We also render the page by doing res.render app.get('', (req, res) => { connection.query('SELECT * FROM user WHERE id = "1"', (error, rows) => { // Once done, release connection if (error) throw error; if (!error) { res.render('index', { rows }); } }); }); app.post('', (req, res) => { let sampleFile; let uploadPath; if (!req.files || Object.keys(req.files).length === 0) { return res.status(400).send('No files were uploaded.'); } // name of the input is sampleFile sampleFile = req.files.sampleFile; uploadPath = __dirname + '/upload/' + sampleFile.name; console.log(sampleFile); // Use mv() to place file on the server sampleFile.mv(uploadPath, function (err) { if (err) return res.status(500).send(err); connection.query('UPDATE user SET profile_image = ? WHERE id ="1"', [sampleFile.name], (err, rows) => { if (!err) { res.redirect('/'); } else { console.log(err); } }); // res.send('File uploaded!'); }); }); app.listen(port, () => console.log(`Listening on port ${port}`));
In our Views -> Layouts folder we need to create our EJS template. The <%- body -%> is where our index.ejs page will render:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="/css/main.css"> </head> <body> <div class="wrapper"> <%- body -%> </div> </body> </html>
Now let’s create our index.hbs page, with our form and a loop to display the record from the database:
<form action="/" method="POST" encType="multipart/form-data"> <h3>Upload Profile Photo</h3> <input type="file" name="sampleFile" accept="image/*" /> <input type="submit" class="btn btn-primary"> </form> <div class="card"> <% for(var i=0; i < rows.length; i++) { %> <img class="card__image" src="<%- rows[i].profile_image %>" loading="lazy" alt="User Profile"> <h1 class="card__title"><%- rows[i].name %></h1> <div class="card__job"><%- rows[i].job_title %></div> <p class="card__about"> <%- rows[i].description %> </p> <button type="button" class="btn btn-primary">View Profile</button> <% } %> </div>
That’s it. The clean code is available on the GitHub link below with fewer explanation comments.
Demo Video Loop
Demo of uploading an image and saving the record to a MySQL Database:
Thank you for reading this article. Please consider subscribing to my YouTube Channel.
More Resources:
Its says ejs layouts but it looks like it is using hbs?
For some reason, I had handlebars in packages.json, but it’s all EJS. Thanks for this, Frederick I’ve updated the article. I need to upload this to Github as well.
You’re awesome dude! Seriously!
Thanks, Jacques! I appreciate it! 👊😎
Thank you a lot, buddy! This is what I just needed! 😎💪
👊😎