Updating / Deleting a Subdocument in the MongoDB Collection

Note Use the mongodb shell to execute the codes.

Say I have one student document below

{ "_id" : 4, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 8 }, { "grade" : 85, "mean" : 90, "std" : 5 }, { "grade" : 85, "mean" : 90, "std" : 5 }, { "grade" : 85, "mean" : 95, "std" : 6 }, { "grade" : 90, "mean" : 85, "std" : 5 } ] } 

We have two problems:

Problem 1 : let's say you want to update all subdocuments with _id = 4 && & grades.grade = 85 && grades.std = 5, with std = 6 you will write as follows

 db.students.update( {'$and':[ { _id: 4},{ "grades.grade": 85 }, {"grades.std": 5 } ]}, { $set: { "grades.$.std" : 6 } } ); 

Now, if you execute the statement above several times (3 times), then ideally it should update the 2nd, 3rd subdocuments

But the last subdocument is also updated by beacause, it has std = 5 match, but we set the condition as $, not $ or, and then how is the last document updated?

Problem 2: Now suppose you want to delete the subdocument itself that matches the query criteria. I tried the following instruction

 db.students.update({_id:4,'grades.grade':85},{'$unset':{'grades.$':1}}) 

because $ unset will put null in case of subdocuments / arrays, how to solve this problem?

How to replicate in mongodb console?

 db.students.insert( { "_id" : 4, "grades" : [ { grade: 80, mean: 75, std: 8 }, { grade: 85, mean: 90, std: 5 }, { grade: 85, mean: 90, std: 5 }, { grade: 85, mean: 95, std: 6 }, { grade: 90, mean: 85, std: 5 } ] }); 
+6
source share
4 answers

The $$ operator updates only the first match:

 db.students.insert({ "_id" : 4, "grades" : [ { grade: 80, mean: 75, std: 8 }, { grade: 85, mean: 90, std: 5 }, { grade: 85, mean: 90, std: 5 }, { grade: 85, mean: 95, std: 6 }, { grade: 90, mean: 85, std: 5 } ]}); 

To upgrade, you need to target using $elemMatch as follows:

 db.students.update( { _id: 4, "grades": {$elemMatch: {"grade": 85, "std": 5 }}}, { $set: { "grades.$.std" : 6 } }); 

However, you have two classes that correspond to {"grades.grade": 85, "grades.std": 5} and $ , only update the first, so you need to loop until everyone is up to date:

 db.students.update( { _id: 4, "grades": {$elemMatch: {"grade": 85, "std": 5 }}}, { $set: { "grades.$.std" : 6 } }) while (db.getLastErrorObj()['n'] > 0) { db.students.update( { _id: 4, "grades": {$elemMatch: {"grade": 85, "std": 5 }}}, { $set: { "grades.$.std" : 6 } }) } 

Problem 2 : the same thing applies - you need to bind the corresponding elements to $pull :

 db.students.update({_id:4,'grades': {$elemMatch: {'grade':85}}}, {'$pull': {'grades': {'grade':85}}}) 
+10
source

You need to use $ elemMatch to match inside the array. The query rules in MongoDB indicate that for array element conditions, any array element in which any of the conditions is satisfied is considered a match. With $elemMatch all conditions must match the same element.

+2
source

The dot notation corresponds to the documents that its criteria can be met in any of the elements of the array.

If you want to match only those documents that meet all your criteria in one element of the array (at least), then as drmirror already answered, you need to use the $ elemMatch operator, see also: $ elemMatch Operator

In your case, it will be:

 db.students.update( {'$and':[ { _id: 4},{ "grades":{"$elemMatch": {"grade": 85, "std": 5 }}} ]}, { $set: { "grades.$.std" : 6 } } ); 

In the second part of your question, how to remove array elements, see the next post.

In mongoDb, how to remove an element of an array by its index

In short, this is a two-step operation that first sets the element to null (as you already did), and then turn off its $ pull (s).

0
source

For issue # 1, refer to: fooobar.com/questions/47224 / ...

Essentially, you will need to create an array of what you want to install manually.

0
source

Source: https://habr.com/ru/post/952187/


All Articles