skip to Main Content

I am trying to use MondodDB bulkWrite for the first time. I want to update multiple documents and remove ids that match the filter that I provided. I read that I could use MongoDB bulkWrite for this action. For this application, there is a Post model and User model. The Post model has an object value called postLikes which contains array of likes. These likes are simply the userId of the user who liked the post. So, I would like to remove their ids from this postLikes array when a selected user is deleted. Selected users to be deleted could be more than 2. When they are selected, their ids are passed as array to the backend in a variable called selectedIds. It is these ids that I would like to update the Post model and remove them from the postLikes array. This can only happen if there is a like by selected user.

It is a MERN stack application.
Here is my code:

const deleteSelectedUsers = async (req, res)=>{
    const {selectedIds} = req.body;// this is an array of selected ids sent from frontend
     //find all posts
    const posts = await Post.find();
    //get filter and return all posts with likes.
    const filteredPost = posts.filter((singleFilter) => singleFilter.postLikes.length !== 0)

     const updatedPosts = filteredPost.map((obj)=>{
    
        selectedIds.map((single)=>{
            //this checks to ensure that there is a like by the user and only that id is removed
            if(obj.postLikes.includes(single)){
               return {
                    updateOne: {
                        filter: { _id: obj._id },
                        update: { $pull: { postLikes: single } },
                    },
                    };
            }
            //console.log(obj.postLikes.includes(single))
        })
    })
  Post.bulkWrite(updatedPosts).then((res) => {
    console.log("Documents Updated", res.modifiedCount)
    })
  
  }
  }

No response from this code at all and update not made. How best can I achieve this?

2

Answers


  1. This is because you’re using .map inside another .map without even returning inside the first .map. This is generating an array of undefined values. From what I understand the question, a better solution would be:

    const findIntersection = (array1, array2) => {
      return array1.filter((elem) => {
          return array2.indexOf(elem) !== -1;
      });
    }
    
    const filteredPost = posts.filter((singleFilter) => {
      const intersection = findIntersection(selectedIds, singleFilter.postLikes);
      return singleFilter.postLikes.length !== 0 && intersection.length !== 0;
    });
    
    const updatedPosts = filteredPost.map((obj)=>{
      const intersection = findIntersection(selectedIds, obj.postLikes);
      return {
        updateOne: {
          filter: { _id: obj._id },
          update: { $pull: { postLikes: { $in: intersection } } },
        },
      };
    });
    

    With the updated code, updatedPosts now contain correct mongoose/mongodb commands. Note the use of $in here. Since you want to remove from postLikes multiple matching values, rather than creating separate updateOnes for each matching value we’re sending all of them in a single udpateOne with the use of $in.

    You could trim down your code even further which is avoiding the finding of the intersection since $in takes care of that part. {$pull : { postLikes: { $in: [...] }}} will ensure that if the value inside the array matches any element in the specified array, it will remove that. Example:

    const updatedPosts = filteredPost.map((obj)=>{
      return {
        updateOne: {
          filter: { _id: obj._id },
          update: { $pull: { postLikes: { $in: selectedIds } } },
        },
      };
    });
    
    Login or Signup to reply.
  2. So, this is how I solved my problem after almost giving up.
    I stored the ids the admin selected in a variable like this:

    cost {selectedIds} = req.body;
    

    I found all the available posts first like this:

    const posts = await Post.find();
    

    Then, I filtered out posts that have no likes at all:

    const filteredPost = posts.filter((singleFilter) => singleFilter.postLikes.length !== 0)
    

    I returned the filtered posts ids like this:

      const newPost = filteredPost.map((singleMap) => singleMap._id);
    

    Then, I removed the selected users’ ids from the filtered posts; postLikes like this using mongoose method:

      const updated = await Post.updateMany({ _id: {$in:  newPost} }, { $pull: { postLikes: { $in: selectedIds } } })
    

    What I discovered is that the mongoose $in needed to be used while passing the filtered posts id.
    Everything is working fine. This can help anyone facing similar challenge.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search