Store images in MongoDB, the Cloudinary way
The easiest way to store images in MongoDB
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.
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 ๐โโ๏ธ.