Reputation: 315
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
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
Reputation: 133
These are my thoughts:-
Use promises instead of callback.
Use of promise.all to concatenate your requests and execute them simultaneously.
Upvotes: 0