Remove array from objects field in MongoDB

I am trying to remove an element of Array just by finding it via the ObjectId in the array element. Following MongoDB opposite of $addToSet to '$removeFromSet', I should've been able to do:

db.collection.update(
  {name: 'nameOfNode'}, 
  {$pull: { activities: ["5e7d16e9736bb64bdd158c13"]}})

or

db.collection.update(
  {name: 'nameOfNode'}, 
  {$pull: { activities: ["5e7d16e9736bb64bdd158c13", "Materi"]}})

Yet both of these codes above doesn't work, does if there is another way to remove them by just one single value, or if that isn't possible, remove them with the two values?

current data schema

Note: I have removed some confidential information from the screenshot, hence the supposed gaps between the letters are not spaces, but covered texts. The strings I've tried to use to refer to them are identical though, no difference.

Upvotes: 1

Views: 197

Answers (1)

Joe
Joe

Reputation: 28326

I see 2 problems with the code: - The value is not a member of the activities array, it is a member of an array contain in the activities array - Searching for a string like activities: ["5e7d16e9736bb64bdd158c13"] will not match a value of type ObjectId.

I ran a quick demonstration of matching an ObjectId:

MongoDB Enterprise replset:PRIMARY> db.updtest.find()  
{ "_id" : ObjectId("5e7d354ccede22b56b5335bc"), "name" : "nameOfNode", "activities" : [ [ ObjectId("5e7d354ccede22b56b5335b9"), "Check-in" ], [ ObjectId("5e7d354ccede22b56b5335ba"), "Materi" ], [ ObjectId("5e7d354ccede22b56b5335bb"), "Materi" ] ] }

MongoDB Enterprise replset:PRIMARY> db.updtest.update({"name" : "nameOfNode"},{$pull:{"activities.0":ObjectId("5e7d354ccede22b56b5335b9")}})  
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

MongoDB Enterprise replset:PRIMARY> db.updtest.find()  
{ "_id" : ObjectId("5e7d354ccede22b56b5335bc"), "name" : "nameOfNode", "activities" : [ [ "Check-in" ], [ ObjectId("5e7d354ccede22b56b5335ba"), "Materi" ], [ ObjectId("5e7d354ccede22b56b5335bb"), "Materi" ] ] }

Note that while this successfully removes the ObjectId value, it does not remove the containing array, which is what I think you wanted.

If you are using MongoDB 4.2, you could use $filter to remove the entire subelement, like:

db.updtest.update(
      {"name" : "nameOfNode"},
      [ {$set:{
         activities:{
             $filter:{
                 input:"$activities",
                 cond:{$ne:["$this.0",ObjectId("5e7d16e9736bb64bdd158c13")]}
             }
          }
      }}]
)

If you can modify the schema, insert activities as objects instead of as sub-arrays. For example, if each activity were of the form {id:... type: ...}, you could match the specific id using $pull:

MongoDB Enterprise replset:PRIMARY> db.updtest.find()
{ "_id" : ObjectId("5e7d3939cede22b56b5335c4"), "name" : "nameOfNode", "activities" : [ { "id" : ObjectId("5e7d3939cede22b56b5335c1"), "type" : "Check-in" }, { "id" : ObjectId("5e7d3939cede22b56b5335c2"), "type" : "Materi" }, { "id" : ObjectId("5e7d3939cede22b56b5335c3"), "type" : "Materi" } ] }

MongoDB Enterprise replset:PRIMARY> db.updtest.update({"name" : "nameOfNode"},{$pull:{"activities":{id:ObjectId("5e7d3939cede22b56b5335c2")}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

MongoDB Enterprise replset:PRIMARY> db.updtest.find()
{ "_id" : ObjectId("5e7d3939cede22b56b5335c4"), "name" : "nameOfNode", "activities" : [ { "id" : ObjectId("5e7d3939cede22b56b5335c1"), "type" : "Check-in" }, { "id" : ObjectId("5e7d3939cede22b56b5335c3"), "type" : "Materi" } ] }

Upvotes: 2

Related Questions