How to delete data from child and also its image data on server if we delete parent in nodejs mongodb

I have a database in which the user is a parent and it has some child documents child document has image data too and those images are stored in the AWS s3 bucket. I used MongoDB middleware remove to perform cascade delete. If I delete parents then the data from the child table is also deleted but the image data remains in the s3 bucket. How can I implement the logic that image data should also be deleted from the server on deleting the parent? I also wrote AWS SDK delete APIs but how can I connect them to the parent document?

// This is the parent delete API

function user_delete(req, res, next) {
    User.findOne({ _id: req.params.id })
        .then(user => {
            if (!user) {
                return next('The user you requested could not be found.')
            }

            Child.remove({ userId: user._id }).exec();
            user.remove();
            return res.status(200).send('User deleted');

        }).catch(err => {
            console.log(err)
            if (err.kind === 'ObjectId') {
                return next(res.status(404).send({
                    success: false,
                    message: "User not found with id "
                }));
            }
            return next(res.status(500).send({
                success: false,
                message: "Error retrieving User with id "
            }));
        });
};
router.delete('/delete/:id', user_delete);

// Delete function for aws SDK delete a file from s3

function deleteFileStream(fileKey, next) {
    const deleteParams = {
        Key: fileKey,
        Bucket: bucket_name,
    }
    s3.deleteObject(deleteParams, (error, data) => {
        next(error, data)
    })
}
exports.deleteFileStream = deleteFileStream;

// Child delete document API

function delete_child(req, res, next) {
    Child.findById(req.params.id)
        .then(child => {
            if (!child) {
                return next(res.status(404).send({
                    success: false,
                    message: "child not found with id " + req.params.id
                }));
            }

            // deleting the images of questions also if it has image
            if(question.file !== '') {
                const url_parts = url.parse(question.file, true);
                const datas = url_parts.pathname.split('getImage/')
                const filekey = datas.pop();
                console.log(filekey);
                deleteFileStream(filekey); // calling the delete function
            }
            child.remove()
            return res.send({
                success: true,
                message: "child successfully deleted!"
            });
        }).catch(err => {
            if (err.kind === 'ObjectId' || err.name === 'NotFound') {
                return res.status(404).send({
                    success: false,
                    message: "child not found with id " + req.params.id
                });
            }
            return res.status(500).send({
                success: false,
                message: "Could not delete question with id " + req.params.id
            });
        });
}
router.delete('/delete/:id', delete_child);

If I call the child API the image is also deleted from the server as I am deleting it but if I delete the parent the child is deleted but not the image. Can anybody tell me, please? I am struggling with this use case.

@Kushagra_Kesav this is my user model(parent)

const User = mongoose.model(‘User’, new mongoose.Schema({

name: {

    type: String,

    required: true

},

email: {

    type: String,

    required: true,
},

password: {

    type: String,

    required: true,

},

profilePictureURL: {

    type: String

},

}));

//this is the child model

const question = new mongoose.Schema({

question: {
    type: String,
    required: true
},
imageUrl: {
    type: String,
    require: false
},
userId: {
    type: Schema.Types.ObjectId,
    required: true,
    ref: "user"
},

})

1 Like

Hi :wave: @Naila_Nosheen,

The userModel I’m assuming here:

{
_id: ObjectId(...),
name: "Naila_Nosheen",
profilePictureURL: "https://s3.us-west-2.amazonaws.com/mybucket/image01.jpg",
...
}

Similarly, the childModel:

{
_id: ObjectId(...),
question: "What is your hobby?"
imageUrl: "https://s3.us-west-2.amazonaws.com/mybucket/question_image01.jpg"
userId: ObjectId(...)
}

Here, I’m suggesting the single function using multiple promises, which will delete the user and child image data from S3 after it gets deleted from the MongoDB databases.

var path = require("path")

function user_delete(req, res) {
  const user = User.findById(req.params.id);
  const child = Child.find({ userId: user._id });

  const fileName = path.basename(child.imageUrl)
  const keyName = path.basename(user.profilePictureURL)

  // var user.profilePictureURL = "https://s3.us-west-2.amazonaws.com/mybucket/image01.jpg"
  // const keyName = path.basename(user.profilePictureURL) // "image01.jpg"

  //Deleting the user from the DB
  User.findByIdAndRemove(req.params.id)
    .then(data => {
      if (!data) {
        console.log({ message: "User not found with id " + req.params.id });
        return;
      }

      //Deleting the Image from the S3 bucket
      deleteFileStream(keyName, (error, data) => {
        if (error) {
          console.log({message: error.message });
          return;
        }
        console.log({ message: "<Message>" });
      })
    }).then(() => {

      //Deleting the child from the DB
      Child.findByIdAndRemove(child._id)
        .then(data => {
          if (!data) {
            console.log({ message: "Child not found with id " + child._id });
            return;
          }

          //Deleting the Image of child from the S3 bucket
          deleteFileStream(fileName, (error, data) => {
            if (error) {
              console.log({ message: error.message });
              return;
            }
            console.log({ message: "<Message>" });
          })
        });
    });
}

Note that this is an untested example and may not work in all cases. Please do the test any code thoroughly with your use case so that there are no surprises.

I hope it answers your questions. Please let us know if you have any follow-up questions.

Regards,
Kushagra

2 Likes

Thank you so much @Kushagra_Kesav for your solution. I want to ask one thing if the parent has more than one child then the same process would be used for all children?

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.