Skip to content Skip to sidebar Skip to footer

Using Multer to Upload Files React Mongo

How-do-you-do, in this tutorial nosotros volition learn how to upload files direct to MongoDB using GridFS specification.

If you recollect TLDR; only check the finish lawmaking here.

The official docs explicate when to apply this specification for uploading files. Which is summarized in the following:

  • If your filesystem limits the number of files in a directory, you can use GridFS to shop as many files as needed.

  • When you lot want to access data from portions of large files without having to load whole files into retentivity, yous can use GridFS to recall sections of files without reading the entire file into memory.

  • When you want to keep your files and metadata automatically synced and deployed across a number of systems and facilities, you lot tin utilise GridFS. When using geographically distributed replica sets, MongoDB can distribute files and their metadata automatically to a number of mongod instances and facilities.

Since, GridFS stores files in chunks. The following are the collections created:

  • chunks stores the binary chunks.
  • files stores the file's metadata.

Prerequisites

  1. NodeJS LTS
  2. MongoDB installed on your local machine
  3. a Code Editor

Setting up a local NodeJS server

Become to your control line, and type

                        

This will generate an package.json file with default values.

Then install all the dependencies required for this project

          

npm install express mongoose ejs multer multer-gridfs-storage

Create a file named app.js in the root of the project. Require the necessary packages for creating a server.

          

const limited = require ( 'limited' ) ; const app = express ( ) ; app . use ( limited . json ( ) ) ; app . set ( 'view engine' , 'ejs' ) ; const port = 5001 ; app . mind ( port , ( ) => { console . log ( 'server started on ' + port ) ; } ) ;

It will exist amend for u.s. to create scripts to run the spider web app from the command line, go to your parcel.json file and on the scripts cardinal, add the following:

          

"scripts" : { "get-go" : "node app.js" , "dev" : "nodemon app.js" }

and then run, npm showtime and the server should start on the port 5001. You should run across one log on the command line stating that server started on 5001 .

Connecting to Database, Initializing GridFsStorage and Creating a Storage

Require all the necessary packages

          

const crypto = require ( 'crypto' ) ; const path = require ( 'path' ) ; const mongoose = require ( 'mongoose' ) ; const multer = require ( 'multer' ) ; const GridFsStorage = require ( 'multer-gridfs-storage' ) ;

Mongoose is an ORM for MongoDB which volition be used for this tutorial. Multer is a NodeJS middleware which facilitates file uploads. And GridFsStorage is GridFS storage engine for Multer to store uploaded files directly to MongoDB. Crypto and Path will be used to create a unique proper noun for the file uploaded.

          

// DB const mongoURI = 'mongodb://localhost:27017/node-file-upl' ; // connection const conn = mongoose . createConnection ( mongoURI , { useNewUrlParser : truthful , useUnifiedTopology : true , } ) ;

Now, Initializing the GridFsStorage

          

// init gfs let gfs ; conn . one time ( 'open' , ( ) => { // init stream gfs = new mongoose . mongo . GridFSBucket ( conn . db , { bucketName : 'uploads' , } ) ; } ) ;

Here we are using the native nodejs-mongodb-drive which the mongoose uses and creating a GridFSBucket, we are passing the db to the saucepan, you lot tin come across nosotros are giving i saucepan name, this bucket name volition be used a name of a collection.

          

// Storage const storage = new GridFsStorage ( { url : mongoURI , file : ( req , file ) => { return new Hope ( ( resolve , reject ) => { crypto . randomBytes ( xvi , ( err , buf ) => { if ( err ) { return pass up ( err ) ; } const filename = buf . toString ( 'hex' ) + path . extname ( file . originalname ) ; const fileInfo = { filename : filename , bucketName : 'uploads' , } ; resolve ( fileInfo ) ; } ) ; } ) ; } , } ) ; const upload = multer ( { storage , } ) ;

Now we are initializing the storage as per Multer GridFS and creating random bytes using the randomBytes method present on the crypto library.

Hither nosotros are using the Promise constructor to create a promise, which so resolves with the fileInfo object. This step is optional equally you tin only pass a url key and the bucket will work only fine and non change the file name. For example y'all can use similar the post-obit :

          

const storage = new GridFsStorage ( { url : mongoURI } ) ;

Adjacent lets ready our frontend with a template engine and configure limited to render the template.

Creating the view

Create a new folder named views in the root of the binder, and inside it create a file named alphabetize.ejs. Here we will store our front end view. I will not diameter you guys will the HTML creation and just mail service the code for information technology. I am using bootstrap for fast prototyping.

          

<! DOCTYPE html > < html lang = " en " > < caput > < meta charset = " UTF-8 " /> < meta name = " viewport " content = " width=device-width, initial-scale=1.0 " /> < meta http-equiv = " X-UA-Compatible " content = " ie=edge " /> < link rel = " stylesheet " href = " https://stackpath.bootstrapcdn.com/bootstrap/iv.iii.1/css/bootstrap.min.css " /> < title > Mongo File Upload </ championship > </ head > < body > < div grade = " container " > < div class = " row " > < div class = " col-md-6 k-machine " > < h1 class = " my-4 " > Lets upload some stuff </ h1 > < form action = " /upload " method = " post " enctype = " multipart/form-data " > < div class = " custom-file mb-3 " > < input blazon = " file " class = " custom-file-input " proper noun = " file " id = " file1 " onchange = " readSingleFile ( this . files ) " /> < characterization course = " custom-file-label " for = " file1 " id = " file-label " > Cull file </ label > </ div > < input blazon = " submit " value = " Submit " grade = " btn btn-main btn-block " /> </ form > </ div > </ div > </ div > < script src = " https://code.jquery.com/jquery-iii.3.i.slim.min.js " > </ script > < script src = " https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.xiv.vii/umd/popper.min.js " > </ script > < script src = " https://stackpath.bootstrapcdn.com/bootstrap/4.3.one/js/bootstrap.min.js " > </ script > < script > function readSingleFile ( eastward ) { const name = e [ 0 ] . name ; certificate . getElementById ( 'file-characterization' ) . textContent = name ; } </ script > </ trunk > </ html >

Setting up the express app to return the view. Gear up the view engine middleware to ejs

          

... . app . utilize ( express . json ( ) ) ; app . set ( "view engine" , "ejs" ) ; ... . app . become ( "/" , ( req , res ) => { res . render ( "index" ) } )

Then start the server again, go to the browser and open http://localhost:5001, and you should see 1 folio rendered with the view nosotros just created.

Alt Text

Create Request to handle the class submit and upload the file

          

app . post ( '/upload' , upload . single ( 'file' ) , ( req , res ) => { res . redirect ( '/' ) ; } ) ;

As we already did nigh of our heavy lifting while creating a storage bucket and multer take cares of the rest. We just need to laissez passer the middleware and then just redirect to the same url.

The tricky function is to download or in this example stream the information from the GridFS storage bucket and return the image, for that we will create a route for showing an image that volition take the name of the file as an argument or passed as a road param.

          

app . get ( '/epitome/:filename' , ( req , res ) => { // console.log('id', req.params.id) const file = gfs . observe ( { filename : req . params . filename , } ) . toArray ( ( err , files ) => { if ( ! files || files . length === 0 ) { return res . status ( 404 ) . json ( { err : 'no files exist' , } ) ; } gfs . openDownloadStreamByName ( req . params . filename ) . pipe ( res ) ; } ) ; } ) ;

On the gridfs bucket we go access to many methods one such is find, which is very similar to normal find in MongoDB and accepts a filename as a offset argument and and then we are converting the result to an array and check if there is any file with such filename and if in that location is we utilize some other method which is present on the gridfs bucket chosen openDownloadStreamByName which then once more takes the filename so we employ the pipe to return the response to the client.

Now upwardly until at present, we tin get the image with the above route but no manner to render it on our view, so let's create a method inside the road where we were rending our alphabetize.ejs page.

          

... . app . get ( "/" , ( req , res ) => { if ( ! gfs ) { console . log ( "some mistake occured, check connexion to db" ) ; res . send ( "some error occured, check connectedness to db" ) ; process . exit ( 0 ) ; } gfs . find ( ) . toArray ( ( err , files ) => { // check if files if ( ! files || files . length === 0 ) { return res . render ( "index" , { files : false } ) ; } else { const f = files . map ( file => { if ( file . contentType === "image/png" || file . contentType === "image/jpeg" ) { file . isImage = truthful ; } else { file . isImage = false ; } return file ; } ) . sort ( ( a , b ) => { return ( new Date ( b [ "uploadDate" ] ) . getTime ( ) - new Appointment ( a [ "uploadDate" ] ) . getTime ( ) ) ; } ) ; render res . render ( "index" , { files : f } ) ; } } ) ; } ) ; ... .

Here yous can come across a lot of optional lawmaking similar the sorting of the array and y'all can skip those.

At present, On the template, nosotros loop over the files sent and and then show the images beneath the form. Nosotros volition only return the files which are of type jpg or png, that check can be upgraded by using a regex and depends on the personal preference.

          

< hr /> <% if(files) { %> <% files.forEach(part(file) {%> < div form = " card mb-iii " > < div class = " card-header " > < div grade = " carte du jour-title " > <%= file.filename %> </ div > </ div > < div class = " card-body " > <% if (file.isImage) { %> < img src = " image/<%= file.filename %> " width = " 250 " alt = " " class = " img-responsive " /> <%} else { %> < p > <% file.filename %> </ p > <% } %> </ div > < div class = " card-footer " > < course action = " /files/del/<%= file._id %> " method = " post " > < button blazon = " submit " grade = " btn btn-danger " > Remove </ button > </ form > </ div > </ div > <%}) %> <% } else { %> < p > No files to show </ p > <% } %>

You tin can see there is one remove button on the higher up code, then let u.s.a. create ane delete route to remove the file from the database.

Alt Text

          

// files/del/:id // Delete chunks from the db app . mail ( '/files/del/:id' , ( req , res ) => { gfs . delete ( new mongoose . Types . ObjectId ( req . params . id ) , ( err , data ) => { if ( err ) render res . condition ( 404 ) . json ( { err : err . message } ) ; res . redirect ( '/' ) ; } ) ; } ) ;

Here we get the id as a string so that needs to be converted into a mongodb objectid and then only the saucepan method tin delete the file with the corresponding id. I kept things simple past not using the delete HTTP method here you are costless to use it if you lot feel like, a mail asking only works fine hither.

Decision

As we can come across MongoDB provides a dainty solution to store files on the database and can come up handy while creating WebApps with less storage facility, only keep in mind you can only store documents up to 16mb.

weatherfordyoulded.blogspot.com

Source: https://shubhambattoo.in/blog/uploading-files-to-mongodb-with-gridfs-and-multer-using-nodejs

Enregistrer un commentaire for "Using Multer to Upload Files React Mongo"