How to delete a specific nested subdocument completely from an document

i have the following document

{
        "_id" : ObjectId("605a62eadefa2a09797f1ae3"),
        "address" : [
                {
                        "_id" : ObjectId("605a62eadefa2a09797f1ae4"),
                        "street" : "King AS",
                        "state" : "CA",
                        "zip" : 12111
                },
                {
                        "_id" : ObjectId("605a62f9defa2a09797f1ae5"),
                        "street" : "123 Leon Street",
                        "state" : "CA",
                        "zip" : 12121
                }
        ],
        "firstName" : "James",
        "__v" : 1
}

i wanted to remove the nested address document completely but somehow leaves me with that id value, instead of being completely empty.

i did something like this:

findOneAndUpdate({ "_id": ObjectId("605a62eadefa2a09797f1ae3"), }, { address: { $elemMatch: {"_id": ObjectId("605a62f9defa2a09797f1ae5")} } }, {$unset:{address: ""}})

but somehow it tends to delete both the nested address object elements. and I’m left with something like this:

address: [ { _id: 605a697be0f5e50a3561dc44 } ]

what i’d ideally want is something like this:
i’d want to delete specific address only and also, remove that subdocument from the nested array subdocuments. Something like this:

lets say i want to delete the second nested documents, then the final documents should look like this:

{
        "_id" : ObjectId("605a62eadefa2a09797f1ae3"),
        "address" : [
                {
                        "_id" : ObjectId("605a62eadefa2a09797f1ae4"),
                        "street" : "King AS",
                        "state" : "CA",
                        "zip" : 12111
                }
        ],
        "firstName" : "James",
        "__v" : 1
}

thank you kindly.

Hi again :wink:
the answer is driven from this post

find({
  "_id": ObjectId("605a62eadefa2a09797f1ae3")
},
{
  address: {
    "$elemMatch": {
      "$ne": [
        "_id",
        ObjectId("605a62f9defa2a09797f1ae5")
      ]
    }
  }
})

Sincerely,

hello,

the statement you provided does not remove the nested document.
its only outputting.

Is there any other way?

My bad, sorry
there you go

.update({
  "_id": ObjectId("605a62eadefa2a09797f1ae3")
},
{
  "$pull": {
    "address": {
      "_id": ObjectId("605a62f9defa2a09797f1ae5")
    }
  }
})
3 Likes

@Imad_Bouteraa Thank you so much brother. I really appreciate you taking time to help me. Your steps really guided me in finishing up my personal project. It means a lot.

So for the answer I think what you wrote was on the right track, but when I tried it did not work,
so I just looked up $pull and looks like we do not have to pass the _id of the document when modifying the nested array sub documents.

Your answer definitely helped tho. Thank you again:

so looks like we can get rid of the document _id and only worry about the nested document _id
and add {multi:true} at the end of the query, like so:

.update(
{},
{
  "$pull": {
    "address": {
      "_id": ObjectId("605a62f9defa2a09797f1ae5")
    }
  }, 
{
  multi: true
}
})
1 Like

Well, without the _id in the query. mongodb will scan the whole collection and “technically” updates every document by removing addresses matching "_id": ObjectId("605a62f9defa2a09797f1ae5").
However if you include "_id": ObjectId("605a62eadefa2a09797f1ae3") mongodb will use the "_id" index and directly targets THE matching document.
So, if you know the "_id" of the concerned document. you absolutely have to take advantage of the "_id" index.
Now, a lot depends on your context:

  • do you want to update one or multiple documents?
  • do you have its/there _id/_ids?

Sincerely,

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.