Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update/remove subdocument in MongoDB collection

Note:Please use mongodb shell to execute the codes.

Let's say i have one student document as 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 2 problems :

Problem 1 : lets say you wants to updates 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 above statement multiple times(3 times) then ideally it should update 2nd,3rd sub-documents

But last sub-document is also getting updated beacause it has std=5 match, but we have given condition as $and not $or, then how come last document is getting updated?

Problem 2 : Now let's say you wants to remove the subdocument itself matching with query criteria. I tried following statement

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

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

How to replicate in your 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 } ] });
like image 487
Mayur Kataria Avatar asked Aug 21 '13 10:08

Mayur Kataria


People also ask

How to update a collection with documents in MongoDB?

To update, use update () along with $set. Let us create a collection with documents − Display all documents from a collection with the help of find () method − > db.demo134.update( ...

What is the difference between update and delete in MongoDB?

The update method is used to modify specific fields in the whole document within the collection of MongoDB. The deleteOne method is used to delete a particular document within the MongoDB collection. Here, we have learned how we can update single or multiple documents upon particular criteria.

How do I update multiple shards in MongoDB?

When the db.collection.update () performs update operations (and not document replacement operations), db.collection.update () can target multiple shards. Starting in MongoDB 4.2, replace document operations attempt to target a single shard, first by using the query filter.

What happens when you execute queries in the MongoDB shell?

When we execute these queries in the MongoDB Shell, it returned the following message in the shell as you can observe in the below image. The returned message of Shell is not more communicating but when you execute the same command on Robo 3T it will show you a message as how many rows get updated in the update query execution.


2 Answers

The '$' operator only updates the first match so given:

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 update you need to target with $elemMatch like so:

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

However, you have two grades that match {"grades.grade": 85, "grades.std": 5} and $ only updates the first so you need to loop until all updated:

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: Same thing applies - you need to loop to $pull matching elements:

db.students.update({_id:4,'grades': {$elemMatch: {'grade':85}}}, {'$pull': {'grades': {'grade':85}}})
like image 174
Ross Avatar answered Oct 17 '22 20:10

Ross


You need to use $elemMatch to match inside an array. The query rules in MongoDB specify that for conditions on array elements, any array element where any of the conditions matches is considered a match. With $elemMatch, all conditions need to match on the same element.

like image 30
drmirror Avatar answered Oct 17 '22 21:10

drmirror