Updating a collection within a promise

Hi guys,

I’ve got a function that sends an SMS via Twilio. Once an SMS is sent, the corresponding sms document in the collection is marked as ‘sent’. This is the way it currently works (without the then bits - works successfully.):

sendSms(mobile, message) //sendSms function triggers Twilio to send an SMS. Twilio returns a promise.
	.then(message=>{
		const sid = message.sid; //Unique ID returned from Twilio to then track the sms status
		console.log(sid); //Successfully logs the sid returned from Twilio
		console.log(sms._id); //Successfully logs the 'id' of the sms document in question (generated prior to the sendSms function execution)
	});
Sms.update({_id: sms._id}, {$set: {status: 'sent'}}); //Works successfully  

I’m trying to evolve the system to track delivery of the message. In order to do this, I need to assign the ID of the message (an ‘sid’) that Twilio returns (within a resolved promise), to the sms document in the collection. So I’ve modified my function to:

sendSms(mobile, message) //sendSms function triggers Twilio to send an SMS. Twilio returns a promise.
	.then(message=>{
		const sid = message.sid;
		console.log(sid); //Successfully logs the sid returned from Twilio
		console.log(sms._id); //Successfully logs the 'id' of the sms in question (generated from before this functions
		// is execurted
		Sms.update({_id: sms._id}, {$set: {status: 'sent', sid}}); //Does not work!
		console.log('Console log post update...'); //Does not log
	});

What am I missing? I don’t see any errors anywhere…

Thanks in advance to anybody who can point me in the right direction!

Sms.update({_id: sms._id}, {$set: {status: ‘sent’, sid}}); //Does not work!

This does not work because you are not setting the property correctly. You need to have something like this:

Sms.update({_id: sms._id}, {$set: {status: ‘sent’, PROPERTY: sid}});

In ES6, {sid} is equivalent to {sid: sid}.

It seem that the twilio-node package (if that’s what you’re using) uses q for Promises. Third party Promise libraries don’t play well with Meteor’s fiber-based server code.

There are ways to fix this:

  1. Use the non-fiber (callback) form of update.
  2. Use the Promise form of insert available in in the rawCollection.
  3. Refactor slightly to use Meteor’s async and await, which will ‘convert’ the q Promise into a Meteor Promise - which behaves well with fibers.

More information here:

1 Like

should have waited a few more seconds for rofallows answer…

Many thanks for the explanation!

Been itching to work with async await so will dive into that and report back!

:slight_smile:

1 Like

Cheers mate, though that isn’t quite the issue here. E.g., replacing the code to remove the sid part completely doesn’t work either:

Sms.update({id: sms.id}, {$set: {status: 'sent'}}); //Does not update to 'sent'

Going to test @robfallows suggestion and see if the q library is at fault here…

Final working solution, documented and explained in @robfallows article - https://blog.meteor.com/using-promises-and-async-await-in-meteor-8f6f4a04f998

import { Promise } from 'meteor/promise';

//send the message and return the response from Twilio
const msg = Promise.await(sendSms(sms.patientMobile, sms.smsBody));
//Extract the id we are after
const sid = msg.sid;
//Update the collection as needed
Sms.update({_id: sms._id}, {$set: {status: 'sent', sid}})
1 Like