Store images in MongoDB, the Cloudinary way

Store images in MongoDB, the Cloudinary way

The easiest way to store images in MongoDB

ยท

6 min read

Hey there everyone. In today's article, we are going to learn about how to store images in MongoDB with the help of Cloudinary. Yes, there are some other ways too to store images in MongoDB, but I found this way really easy and hassle-free.

Keep in consideration that I have used MERN stack when I learned about this, so for different stacks processes may vary. With that said let's move forward

I have divided this article into 4 parts:

1-What's Cloudinary and how to set it up

2-Sending the image to backend

3-Storing the image

4-Final Notes

Let's see what each part holds for us

1-What is Cloudinary and how to set it up?

Cloudinary is an end-to-end image- and video management solution for websites and mobile apps, covering everything from image and video uploads, storage, manipulations, optimizations to delivery. So basically Cloudinary is a platform where you can store your media and retrieve it wherever and whenever you want.

To work with Cloudinary you will need an account, so go to their website , there is a SignUp for Free button on the main page itself, signup from there.

After successful signup, go to the dashboard, under Account Details there are four values, we need three of them for our case (in the next steps) Cloud Name, API Key, API Secret, so keep an eye on them.

Screenshot (79).png

You have successfully created an account in Cloudinary, so let's move forward.

2-Sending the image to the backend

So in the front-end part of your application, you must be having a form where you get the image from the user, that form must be taking multi-part/form-data values so that files will be recognizable in the backend later on

Follow these steps to send an image to the backend

  • create an object out of the FormData constructor
let formData = new FormData();

Now to chose an image, an input field of the file type is needed in the form

<input type="file" id="img"  name="img"  accept="image/*"  
onChange={(e) => formData.append("image", e.target.files[0] )} />

in the input element, you can see the onChange event being handled. It means that whenever an image is chosen append it to the image property of formData, that's how the chosen image will be taken for further processes. We now have our image ready to be sent to the backend

Using Axios to send an image to backend

try {
      const response = await axios.post(IMAGE_UPLOAD_URL, formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      });
      console.log("image uploaded successfully")
    } catch (error) {
      console.log("error occurred  while uploading image", error.data);
    }

So here what's happening is that Axios is taking three arguments

a URL where the request will go

formData, our image data which will be sent along in the request

and a third argument where we tell Axios that we have data of the type form-data, so it handles and passes the data to the backend accordingly This is all we have to do in the front-end part of our app.

3-Storing the image, the backend part

Note: I am assuming that your project is already up and has all required packages installed, we will just revolve around Cloudinary here

In the backend, we need to have Schema for image collection:

const mongoose = require("mongoose");
const { Schema, model } = mongoose;

const ImageSchema = Schema(
  {
   imageUrl: String
  },
  {
    timestamps: true,
  }
);

const Image = model("Image", ImageSchema);

After setting up the schema and model for Image collection we need to wire our app with Cloudinary, let's see how

Note: first navigate inside the file you want to work in, that's where all the code will go

  • for our project install these packages, Cloudinary to connect with it, and for handling files we have express-fileupload

    npm i cloudinary express-fileupload
    
  • make the app ready to accept file data

const app = express();
app.use(fileUpload({ useTempFiles: true }));
  • Earlier we discussed about three values in our Cloudinary dashboard, go to your Cloudinary account take those values, and put them in the .env file of your project(for security purposes) in my case, I have named them: CLOUD_NAME, API_KEY, API_SECRET
const cloudinary = require("cloudinary").v2;
//connection to Cloudinary
cloudinary.config({
  cloud_name: process.env.CLOUD_NAME,
  api_key: process.env.API_KEY,
  api_secret: process.env.API_SECRET,
});

What is happening here is that we are using the Cloudinary package in our file, and to make the connection to Cloudinary we need to pass it three values so that it could authenticate and give us access. We have kept the values in env, so extract them, and assign them to their particular properties

  • now we will take out image data from the request

      const image = req?.files?.image;
      if (image) {
        await cloudinary.uploader.upload(
          image.tempFilePath,
          async (err, result) => {
            if (err) {
              console.log("Error occurred while uploading file");
            } else {
              const imageLink = result.secure_url;
              imageUrl =  image: imageLink;
            }} );
      }
    

    Let's see what is happening in the above piece of code

  • image is taken out of the req object

  • if the image is available, tempFilePath of the image is passed to the Cloudinary image uploader method, where an async operation will happen which can result in two cases:

  • Case 1: Either image upload will fail, User will be prompted with error message and the operation will stop.

  • Case 2: Image will be saved successfully to Cloudinary, and an object will be returned (named result in our case). In that object, there is a property secure_url which will be the URL of the saved image.

    now we need to save this particular URL to MongoDB

const image = new Image(imageUrl)
const response = await image.save()

the image is saved as a string and is a url to the image

Full Code

const ImageUpload = async (req, res) => {
try {
    let imageUrl;
    const image = req?.files?.image;
    if (image) {
    //save to cloudinary
    await cloudinary.uploader.upload(
        image.tempFilePath,
        async (err, result) => {
          if (err) {
          console.log("Error occurred while uploading file");
          } else {
           //get saved image url
            const imageLink = result.secure_url;
            imageUrl =  image: imageLink;
          }} );
    }
//save image in database
const image = new Image(imageUrl)
const response = await image.save()
res.json({status: true, message: "image added successfully", image: response.imageUrl})
}
catch(error){
res.status(500).json({status: false, message: "failed to add image",errorDetail: error?.message})
}
}

That's it. The image is successfully saved in the database.

4-Final Notes

We have successfully got the image from the front-end, stored it in Cloudinary and then stored the image in our database, which was the motive of our article.

Extra: Populate front-end with images saved in database

Populating the front-end with the images saved in the database is fairly simple. You must have the _id of a particular image you want to fetch. Axios can be used to send requests to API with the required image Id and there on the basis of certain operations, the resultant image will be sent in response. Now that response will all the other things will be having a property imageUrl, which will be the URL of our image and can be used as

//image used in src being the fetched image from databse
<img src={imageUrl} alt="text related to content" />

So that's it from this article, if you have reached till here I hope that the article was worth your time.

Any questions, feel free to comment down below, I will try my best to answer them

Until next time ๐Ÿ™‹โ€โ™‚๏ธ.

ย