loading...
Cover image for Uploading Images on MongoDB via nodeJS

Uploading Images on MongoDB via nodeJS

fakorededamilola profile image Fakorede Damilola Updated on ・5 min read

Images are very important on our websites and gives life to the internet. A website without one or two images will be very close to boring.
Images like content can be uploaded on a database for easy access, and today I am going to show you how to easily upload images to MongoDB via nodeJS.
Today I will explain how to

Setup the necessary tools

Before we move forward, we are definitely going to need some packages from NPM (Node Package Manager), such has

  • Express : basically a Node.js web application framework
  • Mongoose : Object Data Modeling (ODM) library for MongoDB and Node.js. It basically handles relationship between data
  • Multer : Is used for uploading files
  • Gridfs-stream : Allows streaming of files to and from mongodb
  • Gridfs : This is a specification for storing and retriviing files that excess the BSON-document size limit of 16MB
npm i express mongoose multer multer-gridfs-storage gridfs-stream
Enter fullscreen mode Exit fullscreen mode

We will be uploading straight to MongoDB atlas, which is a remote MongoDB database, you can also use the local instance but the connection string will be different.

The first thing is to import the required modules, and some core nodeJS modules, and just create the basic server

const express = require('express')
const path = require('path')
const crypto = require('crypto')//to generate file name
const mongoose = require('mongoose')
const multer = require('multer')
const GridFsStorage = require('multer-gridfs-storage')
const Grid = require('gridfs-stream')
const app = express()

// other code here

const PORT =5000
app.listen(PORT,()=>console.log(`Server started on port ${PORT}`))

Enter fullscreen mode Exit fullscreen mode

Next is to add the connection string. If you are using the local instance , yours will probably be 27017...

const mongoURI = "mongodb+srv://fako:fako@nodejspassport-nahp0.mongodb.net"
Enter fullscreen mode Exit fullscreen mode

Next thing is to, create a connection via mongoose, initialize a variable for stream(i.e gfs) and once the connection is open, set the gfs variable to Grid(gridfs-stream) and then pass the collection where our images will be stored to gfs :). Note that this collection will be divided into two, imageUpload.chunk and imageUpload.files

let conn = mongoose.connection
let gfs
conn.once('open', () => {
    //initialize our stream
    gfs = Grid(conn.db, mongoose.mongo)
    gfs.collection('imageUpload')
})

Enter fullscreen mode Exit fullscreen mode

Now, we are going to create a storage object with a given configuration.
The first property will be the uri string which we specified above and the second is called file, a function to control the file storage in the database. It is invoked per file with the parameters req and file in that order and returns an object of a promise that resolves to an object. Some of the property of the object include
filename : The desired filename for the file (default: 16 byte hex name without extension), but you can override this with your given name
content-type : The content type for the file (default: inferred from the request)
bucketname : The GridFs collection to store the file (default: fs)
missing property will use the default

let storage = new GridFsStorage({
    url: uri,
    file: (req, file) => {
        return new Promise(
            (resolve, reject) => {
                       const fileInfo = {
                    filename: file.originalname,
                    bucketName: "imageUpload"
                }
                resolve(fileInfo)

            }
        )
    }
})
Enter fullscreen mode Exit fullscreen mode

Set the multer storage engine to the newly created object, we will use this upload variable has our middleware, so that it actually upload to the database

const upload = multer({ storage })
Enter fullscreen mode Exit fullscreen mode

Upload images to MongoDB

Now to actually upload an image. The upload variable will be added has a middleware and .single will be called on it (because we are uploading a single file each time. You can upload multiple files has an array). You will then pass the name you specified in your input field i.e in the frontend (e.g input type="file" name="upload"

app.post("/upload",upload.single("upload"),(req,res)=>{
res.json({file:req.file})
})
Enter fullscreen mode Exit fullscreen mode

I am not really going to deal with the frontend in this article, but you should have a basic html file with an input file field that on submit will make an AJAX request to localhost:5000/upload, and if you try it out, that should work :). If you were to check atlas or your local database, and you should see the file uploaded.

Get the list of image object (in an array)

To get the list of image object is pretty straight forward,

app.get('/files', (req, res) => {
    gfs.files.find().toArray((err, files) => {
        //check if files exist
        if (!files || files.length == 0) {
            return res.status(404).json({
                err: "No files exist"
            })
        }
        // files exist
        return res.json(files)
    })
})
Enter fullscreen mode Exit fullscreen mode

We are basically using gridfs-stream(gfs) like we will use mongoose. Go to the url with /files and you will see an array of the uploaded files

Get a single image object

To get a single file, all we need is the filename and we can call a findOne on gfs i.e

app.get('/files/:filename', (req, res) => {
    gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
        //check if files exist
        if (!file || file.length == 0) {
            return res.status(404).json({
                err: "No files exist"
            })
        }
        //file exist
        return res.json(file)
    })
})
Enter fullscreen mode Exit fullscreen mode

Display the actual image

To get the image itself,

app.get('/image/:filename', (req, res) => {
    gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
        //check if files exist
        if (!file || file.length == 0) {
            return res.status(404).json({
                err: "No files exist"
            })
        }
        //check if image
        if (file.contentType === 'image/jpeg' || file.contentType === "img/png") {
            //read output to browser
            const readStream = gfs.createReadStream(file.filename)
            readStream.pipe(res)
        } else {
            res.status(404).json({
                err: "Not an image"
            })
        }
    })
})
Enter fullscreen mode Exit fullscreen mode

The first thing to do is check if the file actually exists, if it does, go ahead and check if it is actually an image by looking at it contentType. If is actually an image, then read it to the browser by creating a readStream.

Delete an image

Deleting an image is just as easy, all you have to do is make a delete request i.e

app.delete("/files/:id", (req, res) => {
    gfs.remove({ _id: req.params.id, root: 'imageUpload' }, (err, gridStore) => {
        if (err) {
            return res.status(404).json({ err: err })
        }
        res.redirect("/")
    })
})
Enter fullscreen mode Exit fullscreen mode

and that is how you upload an image to MongoDB via NodeJS. Thank you

You can follow me on twitter @fakoredeDami

Discussion

pic
Editor guide
Collapse
julieg18 profile image
Julie

We will be uploadng straight to MongoDB atlas, which is a remote MongoDB database,

"uploadng" should be "uploading"

Collapse
fakorededamilola profile image
Collapse
fkoeppling profile image
Fabian Köppling

Can you annotate the code what file is meant? Or share the source? Thank you!

Collapse
fakorededamilola profile image
Fakorede Damilola Author

Hello,
I really don't understand the file you mean, but there are basically three main file variables here. The file you get from the storage object has a property (this is from the multer-gridfs-storage), the file you pass has an argument (this is the file the user uploads. and you can get access to properties such has the originalname) and the file which I used has the property of an object which I sent back to the user(this is not really important,you can just easily redirect the person.

Hope that answers you question