We’re gonna show you how to build this Node.js app step by step.
Project Structure
Now look at our project structure:
– views/index.html: contains HTML form for user to upload images.
– routes/web.js: defines routes for endpoints that is called from views, use controllers to handle requests.
– controllers:
home.js returns views/index.html
upload.js handles upload & store images with middleware function.
Open command promt, change current directory to the root folder of our project.
Install Express, Multer, Multer GridFs Storage with the following command:
– We define a storage configuration object with GridFsStorage class.
url: must be a standard MongoDB connection string pointing to the MongoDB database. multer-gridfs-storage module will create a mongodb connection for you automatically.
options: customizes how to establish the connection, specified in the MongoClient.connect documentation.
file: this is the function to control the file storage in the database. The return value of this function is an object with the properties such as: filename, metadata, chunkSize, bucketName, contentType… We also check if the file is an image or not using file.mimetype. Then we add the [timestamp]-bezkoder- prefix to the file’s original name to make sure that the duplicates never occur in MongoDB collection. bucketName indicates that the file will be stored at photos.chunks and photos.files collections.
– Next we use multer module to initialize middleware and util.promisify() to make the exported middleware object can be used with async-await.
– The single() function with the parameter is the name of input tag (in html view: <input type="file" name="file">) will store the single file in req.file.
There are 2 routes:
– GET: Home page for the upload form.
– POST "/upload" to call the upload controller. This is for action="/upload" in the view.
Create Express app server
Finally, we create an Express server.
server.js
const express = require("express");
const app = express();
const initRoutes = require("./routes/web");
app.use(express.urlencoded({ extended: true }));
initRoutes(app);
let port = 3000;
app.listen(port, () => {
console.log(`Running at localhost:${port}`);
});
Run & Check result
On the project root folder, run this command: node src/server.js
The console shows:
Running at localhost:3000
Open browser with url http://localhost:3000/.
Click on Submit button, if the file is uploaded and stored in MongoDB successfully, the browser will show:
For multiple images, we use another function: array() instead of single().
middleware/upload.js
...
// var uploadFile = multer({ storage: storage }).single("file");
var uploadFiles = multer({ storage: storage }).array("multi-files", 10);
var uploadFilesMiddleware = util.promisify(uploadFiles);
module.exports = uploadFilesMiddleware;
array() function limits the number of files to upload each time, the first parameter is the name of input tag (in html view: <input type="file" name="multi-files">), the second parameter is the max number of files (10).
Controller for uploading multiple images
With the controller, we export a new function: uploadFiles.
controllers/upload.js
const upload = require("../middleware/upload");
const uploadFiles = async (req, res) => {
try {
await upload(req, res);
console.log(req.files);
if (req.files.length <= 0) {
return res.send(`You must select at least 1 file.`);
}
return res.send(`Files have been uploaded.`);
} catch (error) {
console.log(error);
if (error.code === "LIMIT_UNEXPECTED_FILE") {
return res.send("Too many files to upload.");
}
return res.send(`Error when trying upload many files: ${error}`);
}
};
module.exports = {
uploadFiles: uploadFiles
};
There is a additional part in the catch() block. We check if the error.code is "LIMIT_UNEXPECTED_FILE" for showing user the message when he tries to upload more than 10 images/files.
Don't forget to change the controller method on router: