4

I have a Node Js-Express backend & Cloudinary for image storage, for adding a blog to a database. I have configured it to enter the basic blog details like title, category, images, etc. All the CRUD operations work very well so far.

A blog has multiple images uploaded with it. If a user has to perform an update operation on a given blog, a user can update one or more images in the DB. But since the images are served through Cloudinary storage, the images need to be updated there also. I am a bit stuck on how to associate the update logic for the same with cloudinary.

This is how my editBlog controller looks so far:

exports.editBlog = async (req, res) => {
    const { id } = req.params;
    const { title, category, content } = req.body;
    const blogImages = req.files; // There might be only single image passed to edit instead of all 3 images (for example) 

    try {
        if (!blogImages) {
            return res.status(400).json({ message: 'No images attached!' });
        }

        const updated_images = await Promise.all(blogImages.map((img) => cloudinaryUploadImage(img.path)));

        const updates = {};

        if (req.body) {
            updates.title = title;
            updates.category = category;
            updates.content = content;
            updates.images = updated_images;
        }

        const updated_data = await Blog.findOneAndUpdate(
            { _id: id },
            {
                $set: updates
            },
            {
                new: true
            }
        );

        if (!updated_data) {
            res.status(200).json({ message: 'Data does not exist' });
            return;
        }
        res.status(200).json({ message: 'Data updated', result: updated_data });
    } catch (error) {
        res.status(500).json({ message: 'Internal server error', error });
    }
};

cloudinaryUploadImage function:

const cloudinaryUploadImage = async image => {
  return new Promise((resolve, reject) => {
      cloudinary.uploader.upload( image , (err, res) => {
        if (err) return res.status(500).send("upload image error")
          resolve({
            img_url: res.secure_url,
            img_id: res.public_id
          }); 
        }
      ) 
  })
}

I don't want to fill up my cloudinary storage with unnecessary files. If one image needs to be replaced, then the old image should be deleted from the storage.

I would really appreciate it if anyone can help me achieve this with just a few tweaks to this code.

Thanks in advance

program_bumble_bee
  • 439
  • 2
  • 25
  • 57

1 Answers1

0

It's not obvious what you are storing in your DB so that you can look up the images on Cloudinary, but if you are storing the img_id (which is the public id on Cloudinary), you can use that to override the original image.

If the user is replacing that particular img_id (public_id) you can do another upload call that includes the parameters public_id and you should also pass in the parameter invalidate set as true so the request invalidates any previous versions of the asset being replaced. The upload call would look like this:

cloudinary.uploader.upload( image , public_id: <public_id>, invalidate: true , (err, res) => { . . . }

This will replace the image on Cloudinary with the new one, and remove it from any cache at the CDN so your blog will get the latest version.

Daniel Mendoza
  • 487
  • 4
  • 6