DEV Community

Cover image for Update an object in nested array in MongoDB
Rajesh Royal
Rajesh Royal

Posted on Edited on

Update an object in nested array in MongoDB

Hello Reader šŸ‘‹

To update an object inside a nested array in MongoDB you can use this approach, Its well tested and working.

Case:

Update nested array objects. See below picture for a better Idea what we are going to do. We will update the object which is nested by 3 levels of array.

{
 discussionList[
  discussionList [
   {
     object-value-to-be-updated.
   }
  ]
 ]
} 
Enter fullscreen mode Exit fullscreen mode

mongodb - update an object inside multilevel nested array

Solution:

public courseCategoryPostCommentReplyUpdate(operation: CommentReplyUpdateMutation): Promise<IDocumentUpdateType> {
    return this.courseCategoryPostCommentsModel.updateOne(
      {
        "postId" : operation.postId,
        'discussionList': {
          '$elemMatch': {
            '_id': operation.commentId,
            "discussionList._id": operation.replyId
          }
        }
      },
      {
        $set: {
          "discussionList.$[outer].discussionList.$[inner].payload": operation.payload,
          "discussionList.$[outer].discussionList.$[inner].isUpdated": true,
          "discussionList.$[outer].discussionList.$[inner].commentUpdateTime": new Date()
        }
      },
      {
        arrayFilters: [
          { "outer._id": operation.commentId},
          {"inner._id": operation.replyId}

      ]
      }
    );
  }
Enter fullscreen mode Exit fullscreen mode

FootNotes - this code is to update the reply of a comment.

That's how you can perform operations on an object in nested array in mongoDB document. You can also update/delete the objects which are having the more level of nesting by just modifying the query.

Example of delete and get

Delete
// Informational Note:
  // Delete nested array values in mongodb


  public courseCategoryPostCommentReplyDelete(operation: CommentReplyDeleteMutation): Promise<IDocumentUpdateType> {
    return this.courseCategoryPostCommentsModel.updateOne(
      {
        'postId': operation.postId,

        'discussionList': {
          '$elemMatch': {
            '_id': operation.commentId,
            'discussionList._id': operation.replyId
          }
        }
      }, {
        $pull: {
          'discussionList.$[outer].discussionList': {
            user: operation.userId,
            _id: operation.replyId
          }
        }
      },
      {
        arrayFilters: [
          { 'outer._id': operation.commentId }
        ],
        multi: false
      }
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

GET

public courseCategoryPostCommentRead(postId: string): Promise<IComment> {
    return this.courseCategoryPostCommentsModel.findOne<IComment>({
      postId: postId
    }).populate('discussionList.user').populate('discussionList.discussionList.user').exec();
  }
Enter fullscreen mode Exit fullscreen mode

I was using GraphQL. You may need to iterate over the result and show the comments/replies as per that.

Please let me know if the code needs an explanation. Thanks šŸ™‚

Top comments (6)

Collapse
 
linkitsoftoffice profile image
linkitsoftoffice

how can I use pull in this? I tried modifying the query but it prompts me up with errors like, pull to a non array value further modifying it gives me, Could not find path "undefined.0.userId" in schema.

Collapse
 
rajeshroyal profile image
Rajesh Royal

@linkitsoftoffice I have updated the post.

Collapse
 
saheb24027824 profile image
Uifoxes

Data :

[
    {
      _id: ObjectId("641050763af868f204dd3ce6"),
      username: 'erkin',
      email: 'erkin-07@hotmail.com',
      password: 'b',
      playlists: [
        {
          _id: 58,
          name: 'asdsa',
          date: '09-01-15',
          musics: [
            {
              name: 'INNA - Cola Song (feat. J Balvin)',
              duration: '3.00'
            },
            { name: 'blabla', duration: '3.00' },
            { name: 'new', duration: '3.00' }
          ]
        }
      ]
    }
  ]
Enter fullscreen mode Exit fullscreen mode

Query

db.test.updateOne(
    {
        username: 'erkin',
        playlists:{$elemMatch: {name:"asdsa" , "musics.name":"blabla"}}

    },
    {
        $set:{"playlists.$[outer].musics.$[inner].duration":"4.00"}
    },
    {
        $arrayFilters:[{"outer.name":"asdsa"},{"inner.name":"blabla"}]
    }
)
Enter fullscreen mode Exit fullscreen mode

Output
MongoServerError: No array filter found for identifier 'outer' in path 'playlists.$[outer].musics.$[inner].duration'

Please help to correct the error

Collapse
 
ssembara profile image
Sebastianus Sembara

where do we get the inner and outer variables?

Collapse
 
rajeshroyal profile image
Rajesh Royal • Edited

You don't have to get those variables.

The inner and outer variables are used as placeholders. If you see in the arrayFilter we are modifying the ._id part of these variables.

Collapse
 
saheb24027824 profile image
Uifoxes

found the issue $arrayFilters , it should be arrayFilters