publicArt33
publicArt33

Reputation: 315

mongoDB updating 2 collections at the same time

I am looking for a different ways to update 2 collections at the same time, in the following case i updating number of cases for a doctor

My Mongo DB document structure:

Doctors Collection:

 { 
    "_id" : ObjectId("5a18a637346826574416a588"), 
    "doc_fname" : "Bob", 
    "doc_lname" : "Smith", 
    "numOfCases" : NumberInt(6), 
    "__v" : NumberInt(0)
 }

CustomerCases Collection:

{ 
    "_id" : ObjectId("5a18c02221344b58585105ea"), 
    "doctor_id" : ObjectId("5a18a637346826574416a588"), 
    "cust_fname" : "test", 
    "cust_lname" : "test", 
    "case_type" : "Crowns", 
    "__v" : NumberInt(0)
}

NodeJS Mongoose Code:

var NewCustomerCase = req.body;


CustomerCases.create(NewCustomerCase, function(err,CustomerCase){
    if(err){
        throw err;
    }
    else{
        var query = {_id:NewCustomerCase.doctor_id};
        // if the field doesnt exsit $set will set q new field
        var update = {
            '$inc': {'numOfCases': 1}
        }
        // when true return the updated document
        var options = {new:true};
        Doctors.findOneAndUpdate(query,update,options,function(err,updatedDocter){
            if(err){
                throw err;
            }
        });
        res.json(CustomerCase);
    }

});

This approach works fine, is there a better way to approach this problem, as far as i know its not possible to execute 2 collection at the same time

Upvotes: 2

Views: 2508

Answers (2)

Mika Sundland
Mika Sundland

Reputation: 18939

If the documents you are updating don't depend on each other you can update them both at the same time. For example by making two promises and then running them at the same time with Promise.all():

const customerPromise = CustomerCases.create(NewCustomerCase);
const doctorPromise = Doctors.findOneAndUpdate(query, update, options);

Promise.all([customerPromise, doctorPromise])
  .then((result) => {
    return res.status(200).json(result);
  }).catch((err) => {
    return res.status(400).json(err);
  });

The promise returned by Promise.all() will be resolved when both the customer and doctor promises are resolved. The documentation is here.

The problem occurs if there is an error. If the customer fails to update the doctor will still increment numOfCases by 1. If the doctor document fails to update the customer case will still be made. So in fact, you do have some dependencies between the documents, and Promise.all() is maybe not such as good solution after all. This is often where transactions come in to play, but transactions in MongoDB is outside the scope of this answer, so I'll just post this link instead.

You already run the DB operations sequentially with callbacks. Here is a more modern way of doing it based on async/await:

try {
  const newCustomerCaseFromDb = await CustomerCases.create(NewCustomerCase);
  const doctorUpdated = await Doctors.findOneAndUpdate(query, update, options);
  return res.status(200).json({ newCustomerCaseFromDb, doctorUpdated });
} catch(err) {
  return res.status(400).json(err);
}

A function that uses await needs the async keyword.

The customer case is created first. If it fails it jumps into the catch block. If it succeeds it continues with finding and updating the doctor. Using await makes it look like synchronous code.

Upvotes: 2

tumulr
tumulr

Reputation: 133

These are my thoughts:-

  1. Use promises instead of callback.

  2. Use of promise.all to concatenate your requests and execute them simultaneously.

Upvotes: 0

Related Questions