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?
CodePudding user response:
This is because you're using .map
inside another .map
without even return
ing 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 updateOne
s 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 } } },
},
};
});
CodePudding user response:
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.