node.jsmongodbexpressmongodb-querymongodb-nodejs-driver

How to add or remove a element in double nested array?


Example of the document:

{
    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'],
                    
                }
            ]
        }
    ]
}

I want to add userid in likesOnReply if users do not exist in likesOnReply, similarly remove userid from likesOnReply if exist.

I have tried like this but not working properly

   await collection('post').findOneAndUpdate(
                {
                    postId: postId,
                    'commentsOnPost.commentId': commentId,
                    'commentsOnPost.repliesOnPost.replyId': replyId
                },
                {

                    $push: { 'commentsOnPost.$[].repliesOnPost.$.likes': userid },
                },

            );

Solution

  • There is no straight way to do both the operation to pull or push in a single query,

    There are 2 approaches,

    1) Find and update using 2 queries:

    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 }
        ]
      }
    )
    

    Playground

    2) Update with aggregation pipeline starting from MongoDB 4.2:

    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"
                ]
              }
            }
          }
        }
      }]
    )
    

    Playgorund