# Store images on MongoDB

Images have become a crucial part of the internet. It's not just web applications that need images, social media has made sure that users not only consume data but also produce and share them. Applications like WhatsApp, Telegram, and Discord also support sharing documents. So, as a backend developer, handling images and storing them on the database is a must. For this tutorial, I am assuming that you are fairly good with ExpressJS and can use Mongoose, or at least know how to use the MongoDB native drivers for NodeJS. I am also assuming that your Express Server is already set up with Mongoose, or that you are using the native MongoDB drivers for NodeJS

## Form encoding
When making a `POST` request, you need to encode the data that is passed along to the backed so that it can be easily parsed. HTML forms provide three methods of encoding:

- **application/x-www-form-urlencoded**: The default mode of encoding. A long string of name-values is created, where each name and value pair is separated by an `=`, and each pair is separated by an `&` so that it can be parsed by the server.
- **multipart/form-data**: This encoding is used when there is a need for files to be uploaded to the server.
- **text/plain**: They have been introduced as a part of the HTML 5 specification, and are not used widely in general.


## Why image handling is different on Express?
When you send form data to the express backend, express is equipped with handling the `application/x-www-form-urlencoded` and the `text/plain` encodings, it cannot process the `multipart/form-data` encoding, which is primarily used for uploading files.  This is where Multer comes in. A node.js middleware that will handle multipart encoded forms for us. 

## Setting up your Schema
You need to define a schema `Upload.js` for the collection where you are going to store your images. If you are using the native MongoDB drivers, you can skip this part. 


```javascript
// Upload.js
const mongoose = require("mongoose");

const UploadSchema = new mongoose.Schema({
  fileName: {
    type: String,
    required: true,
  },
  file: {
    data: Buffer,
    contentType: String,
  },
  uploadTime: {
    type: Date,
    default: Date.now,
  },
});

module.exports = Upload = mongoose.model("upload", UploadSchema);
``` 

In the above schema, the `file` block is the most important one, the rest can be conveniently ignored to match your requirements.

## Setting up multer
Install Multer for your application: 
#### Using npm:
`npm i multer`
#### Using yarn:
`yarn add multer`

Now, let's create a route that will handle file upload. But before that, let's enable our app to use multer in `upload.js`.

```js
// upload.js
const express = require('express')
const multer  = require('multer')
//importing mongoose schema file
const Upload = require("../models/Upload");
const app = express()
//setting options for multer
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
```

This snippet makes sure that the file is parsed and stored in the memory. 
**WARNING**: Make sure that you take steps to make sure that the file being uploaded isn't huge, or else you could be looking at a Denial-of-service threat.
There are some options that you can use in multer. Take a look at them [here](https://github.com/expressjs/multer#multeropts).

## Using multer middleware in your route
Now that you have set up multer successfully, it is time to use it as a middleware in your requests. 

```javascript
app.post("/upload", upload.single("file"), async (req, res) => {
  // req.file can be used to access all file properties
  try {
    //check if the request has an image or not
    if (!req.file) {
      res.json({
        success: false,
        message: "You must provide at least 1 file"
      });
    } else {
      let imageUploadObject = {
        file: {
          data: req.file.buffer,
          contentType: req.file.mimetype
        },
        fileName: req.body.fileName
      };
      const uploadObject = new Upload(imageUploadObject);
      // saving the object into the database
      const uploadProcess = await uploadObject.save();
    }
  } catch (error) {
    console.error(error);
    res.status(500).send("Server Error");
  }
});

```

You can also use `upload.array()` instead of `upload.single()` if you are expecting to receive more than one file from the frontend. More about that [here](https://github.com/expressjs/multer#usage).

#### Code explanation

The middleware `upload.single("image")` is used to tell the server that only one file is being expected from the browser. The argument inside the `upload.single()` tells the name of the file field in the HTML form. Using this middleware enables us to use `req.file` inside the route definition to access the received file. We used `req.file.buffer` and `req.file.mimetype` to save the file on the database. The `buffer` is raw binary data of the file received and we'll store it on the database as it is. The `req.file.mimetype` is also very important for us as it'll tell the browser how to parse the raw binary data, i.e. what to interpret the data as, whether it be a png image or jpeg, or something else. To find out what other information can be accessed from `req.file`, click [here](https://github.com/expressjs/multer#file-information). We had to break the file object into two properties, namely **data**, which contains the raw binary, and the **contentType**, which contains the mimetype. 


## Sending data from Frontend
Remember, multer only accepts `multipart/form-data` for files. That is why we need to set the encoding type to the same on our frontend.
``` html
<form action="/profile" method="post" enctype="multipart/form-data">
  <input type="file" name="avatar" />
</form>
```

## How to convert it back to an image?
Well, there are basically two ways you can do this. You either convert the binary data to the image on the backend and then send it to the frontend, or you send the binary data to the frontend and then convert it to an image. It totally depends on your liking and your use case. How to do it? Well, that article is for another WebDev Monday's.
