我第一次尝试使用MondodDBbulkWrite
。我想更新多个文档并删除与我提供的过滤器匹配的ID。我读到我可以使用MongoDBbulkWrite
来执行此操作。对于这个应用程序,有一个Post模型和User模型。Post模型有一个名为postLikes
的对象值,它包含一个点赞数组。这些点赞只是点赞帖子的用户的userId。因此,我想在删除所选用户时从postLikes
数组中删除他们的ID。要删除的选定用户可能超过2个。当它们被选中时,它们的ids
将作为数组传递到名为selectedIds
的变量中的后端。我想更新Post
模型并将其从postLikes
阵列中删除的正是这些ids
。只有当存在所选用户的点赞时,才会发生这种情况。
它是一个MERN堆栈应用程序。这是我的代码:
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)
})
}
}
此代码根本没有响应,也没有进行更新。我怎样才能最好地做到这一点?
这是因为在另一个.map
中使用.map
,而在第一个.map
中甚至没有使用return
。这将生成一个undefined
值的数组。根据我对这个问题的理解,更好的解决方案是:
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 } } },
},
};
});
有了更新后的代码,updatedPosts
现在包含了正确的mongoose/mongodb命令。注意此处$in
的使用。由于您希望从postLikes
中删除多个匹配值,而不是为每个匹配值创建单独的updateOne
,因此我们将使用$in
在单个udpateOne
中发送所有这些值。
您可以进一步精简代码,这样可以避免找到交集,因为$in
负责处理该部分。{$pull : { postLikes: { $in: [...] }}}
将确保,如果数组中的值与指定数组中的任何元素匹配,它将删除该元素。示例:
const updatedPosts = filteredPost.map((obj)=>{
return {
updateOne: {
filter: { _id: obj._id },
update: { $pull: { postLikes: { $in: selectedIds } } },
},
};
});
所以,这就是我在几乎放弃后解决问题的方法。我将管理员选择的ID存储在一个变量中,如下所示:
cost {selectedIds} = req.body;
我首先找到了所有可用的帖子,如下所示:
const posts = await Post.find();
然后,我过滤掉了根本没有点赞的帖子:
const filteredPost = posts.filter((singleFilter) => singleFilter.postLikes.length !== 0)
我返回了过滤后的帖子ID如下:
const newPost = filteredPost.map((singleMap) => singleMap._id);
然后,我从过滤后的帖子中删除了选定用户的id;postLikes
像这样使用猫鼬方法:
const updated = await Post.updateMany({ _id: {$in: newPost} }, { $pull: { postLikes: { $in: selectedIds } } })
我发现在传递过滤后的posts id时需要使用mongoose$in
。一切都很好。这可以帮助任何面临类似挑战的人。