Uploading images with MongoDB, express, node, and react

Viewed 1146

I have been following this great tutorial on YouTube trying to make a website. However once I deployed it, the images aren't showing because currently they are all saved in a local folder called uploads. This is how it looks like right now:

SERVER SIDE:

var storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, 'uploads/')
    },
    filename: (req, file, cb) => {
        cb(null, `${Date.now()}_${file.originalname}`)
    },
    fileFilter: (req, file, cb) => {
        const ext = path.extname(file.originalname)
        if (ext !== '.jpg' || ext !== '.png') {
            return cb(res.status(400).end('only jpg, png are allowed'), false);
        }
        cb(null, true)
    }
})

var upload = multer({ storage: storage }).single("file")

router.post("/uploadImage", auth, (req, res) => {

    upload(req, res, err => {
        if(err) return res.json({success: false, err})
        return res.json({ success: true, image: res.req.file.path, fileName: res.req.file.filename})
    })
   
});

CLIENT SIDE: image field stores a string (i.e. "uploads\xxxxxxxx.jpg")

function ProductImage(props) {

    const [Image, setImage] = useState();

    useEffect(() => {
        setImage(`http://localhost:5000/${props.detail.image}`)
        

    }, [props.detail])
    
    return(
        <div>
            <img style={{maxWidth: '30vw'}} 
            src={Image} alt="productImg"/>
        </div>
    )
}

So I guess my question now is that how do I go about actually uploading the images to MongoDB, and how would I retrieve them?

2 Answers

first of all, it is not a wise choice to store raw image data on any databases.

you must do 3 things for handling files:

1.create a string field in your data collections for storing the file name and the path you wish to store your image in your host.

  1. upload controller:

in upload controller you can handle logic of your uploads such , storing data , validation about file , and when the file landed in your server you can store the path of that in your database.

3.serve your static file with express :

router.use(
    "/avatar",
    express.static(path.join(__dirname, "../upload/avatar"))
);

If you are storing your uploaded images in the Heroku server, it is an utter waste. Because Heroku Dyno will restart every day which will delete all the extra added data other than data stored during deployment time.

For uploading into MongoDB first you need to store it to the server, multer does that job and later it will be automatically deleted from heroku. Below code encrypts your data and uploads it to a particular document based on id.

//Hashing and uploading to Mongodb 
fs.readFile('your file location', async function (err, data) {
    if (err) {
        console.log(err)
    } else {
        let iv = crypto.randomBytes(16);
        let pass = //I think 32 char password is required
        let cipher = crypto.createCipheriv('aes-256-ctr', pass, iv)
        let crypted = Buffer.concat([iv, cipher.update(data), cipher.final()]);


        console.log("crypted", crypted);
        let dataa = await User.findOne({
            _id: "Id of a MongoDB document"
        })
        //let buffer=new Buffer(data)
        dataa.files.push(crypted)
        await dataa.save()
        console.log("done")
    }

});

Retrieving and decrypting data

let data = await User.findOne({
    _id: "id of a MongoDB document"
})
console.log("dattttt", data.files[index of your image in mongoarray].buffer)


iv = data.files[index of your image in mongoarray].buffer.slice(0, 16);
chunk = data.files[index of your image in mongoarray].buffer.slice(16);
var decipher = crypto.createDecipheriv('aes-256-ctr', "same 32 char password here", iv)
var dec = Buffer.concat([decipher.update(chunk), decipher.final()]);

console.log("dec", dec);
let buffer = new Buffer.from(dec)
console.log("buffer", buffer)
fs.writeFile(`downloadable file location/filename.extension`, buffer, "binary", function (err, written) {
    if (err) console.log(err);
    else {
        console.log("Successfully written");
        res.sendFile((__dirname + `downloaded file location/filename.extension`))
    }
});
Related