Home > Net >  Mongodb : Update multiple documents with different filter value
Mongodb : Update multiple documents with different filter value

Time:11-30

There is a Student collection in my Database as below.

Mongodb Student Collection :

{
    name : 'Rahul',
    age : '15'
}
{
    name : 'Ajay',
    age : '25'
}
{
    name : 'Pinku',
    age : '43'
}
{
    name : 'Vinod',
    age : '30'
}

I am getting an array of data after making a callout to external system for the above students.

[
    {'name':'Ajay','marks':20},
    {'name':'Pinku','marks':12},
    {'name':'Vinod','marks':50},
    {'name':'Rahul','marks':80}
]

My task is to update the Students collection record, with the marks of matching student. Is there a way i can do it in one dml operation, instead of looping through each student document and updating it with marks.

Output should be: Mongod Student Collection :

{
    name : 'Rahul',
    age : '15',
    marks : 80
}
{
    name : 'Ajay',
    age : '25',
    marks : 20
}
{
    name : 'Pinku',
    age : '43',
    marks : 12
}
{
    name : 'Vinod',
    age : '30',
    marks : 50
}

Note : I want to do this inside MondbDB Realm UI, to automate some functionality.

CodePudding user response:

Query

  • pipeline update requires MongoDB >= 4.2
  • students-grades :
    [{'name':'Ajay','marks':20},
    {'name':'Pinku','marks':12},
    {'name':'Vinod','marks':50},
    {'name':'Rahul','marks':80}]
    
    put this variable on reduce "input"
  • find the documents where name is in the array (its best to have an index on name)
  • instead of ["Ajay", "Pinku", "Vinod", "Rahul"] use something like get-names(students-grades) with your driver code
  • $reduce the students-grades, to find for each name the mark all have a mark because they passed the find

Test code here

update(
{"name": {"$in": ["Ajay", "Pinku", "Vinod", "Rahul"]}},
[{"$set": 
   {"mark": 
     {"$reduce": 
       {"input": 
         [{"name": "Ajay", "marks": 20}, {"name": "Pinku", "marks": 12},
          {"name": "Vinod", "marks": 50}, {"name": "Rahul", "marks": 80}],
        "initialValue": "$$REMOVE",
        "in": 
          {"$cond": 
            [{"$eq": ["$$this.name", "$name"]},
              "$$this.marks",
              "$$value"]}}}}}],
{"multi": true})

CodePudding user response:

bulkWrite would be useful in this situation. Map over the input array to generate an array of updateOne operations, then submit them all in bulk.

let input = [
    {'name':'Ajay','marks':20},
    {'name':'Pinku','marks':12},
    {'name':'Vinod','marks':50},
    {'name':'Rahul','marks':80}
];
let operations = input.map(function(student){
   return {updateOne:{filter:{name:student.name},update:{$set:{marks:student.marks}}
};
db.collection.bulkWrite(operations);
  • Related