DEV Community

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

Posted on • Updated 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