问题描述
文档示例:
{
postId:'232323',post:'This is my first post',commentsOnPost:[
{
commentId:'232323_8888',comment:'Congrats',repliesOnPost:[
{
replyId:'232323_8888_66666',reply:'Thanks',likesOnReply:['user1','user5','user3'],}
]
}
]
}
如果用户在 userid
中不存在,我想在 likesOnReply
中添加 likesOnReply
,如果存在,同样从 userid
中删除 likesOnReply
。
我试过这样但不能正常工作
await collection('post').findOneAndUpdate(
{
postId: postId,'commentsOnPost.commentId': commentId,'commentsOnPost.repliesOnPost.replyId': replyId
},{
$push: { 'commentsOnPost.$[].repliesOnPost.$.likes': userid },},);
解决方法
没有直接的方法可以在单个查询中同时执行拉取或推送操作,
有两种方法,
1) 使用 2 个查询查找和更新:
- 使用 arrayFilters 更新嵌套数组元素
-
$push
插入元素 -
$pull
删除元素
var post = await collection('post').findOne({
posted: postId,ommentsOnPost: {
$elemMatch: {
commentId: commentId,repliesOnPost: {
$elemMatch: {
replyId: replyId
likesOnReply: userid
}
}
}
}
});
var updateOperator = "$push";
// FOUND USER ID THEN DO REMOVE OPERATION
if (post) updateOperator = "$pull";
// QUERY
await collection('post').updateOne(
{ postId: postId },{
[updateOperator]: {
"commentsOnPost.$[c].repliesOnPost.$[r].likesOnReply": userid
}
},{
arrayFilters: [
{ "c.commentId": commentId },{ "r.replyId": replyId }
]
}
)
2) Update with aggregation pipeline 从 MongoDB 4.2 开始:
-
$map
迭代commentsOnPost
数组检查条件的循环,如果commentId
匹配,则转到下一个过程,否则返回现有对象 -
$mergeObjects
将当前对象与更新的字段合并 -
$map
迭代repliesOnPost
数组的循环并检查条件,如果replyId
匹配,则转到下一个过程,否则返回现有对象 - 检查
likesOnReply
的条件有userid
然后使用$filter
删除,否则使用$concatArrays
插入
await collection('post').findOneAndUpdate(
{ postId: "232323" },[{
$set: {
commentsOnPost: {
$map: {
input: "$commentsOnPost",in: {
$cond: [
{ $eq: ["$$this.commentId",commentId] },{
$mergeObjects: [
"$$this",{
repliesOnPost: {
$map: {
input: "$$this.repliesOnPost",in: {
$cond: [
{ $eq: ["$$this.replyId",replyId] },{
$mergeObjects: [
"$$this",{
likesOnReply: {
$cond: [
{ $in: [userid,"$$this.likesOnReply"] },{
$filter: {
input: "$$this.likesOnReply",cond: { $ne: ["$$this",userid] }
}
},{
$concatArrays: ["$$this.likesOnReply",[userid]]
}
]
}
}
]
},"$$this"
]
}
}
}
}
]
},"$$this"
]
}
}
}
}
}]
)