What is the use of a callback in rethinkdb's run function - rethinkdb

I'm having trouble understanding why there needs to be a callback after a set of results have been returned (especially as any function can be put into the ReQL).Can someone give an example of how the callback can be used?

I assume you're talking about the JavaScript driver.
The callback is just a normal node-style callback function into which the results are passed. You can use it instead of the promise, e.g.:
r.expr(5).run(conn, function(err, result) {
if (err) { console.log("Error: " + err); }
else { console.log("Result: " + result); }
});
instead of the promise-style version
r.expr(5).run(conn).then(function(result) {
console.log("Result: " + result);
}).catch(function(err) {
console.log("Error: " + err);
});
I hope that helps. It normally doesn't make sense to use both promises and the callback.

Related

Alexa app working locally, returning early on Lambda

So I have multiple calls chained all working and posting the update to a google spreadsheet when I run locally, but when I try and run it on Lambda it just returns early without any errors.
skillService.intent("sampleIntent", {
...
},
function(request,response){
var name = request.slot("NAME");
var category = request.slot("CATEGORY");
var event = request.slot("EVENT");
// slot used for any parts of conversation
var stepValue = request.slot('STEPVALUE');
var sampleHelper = getHelper(request);
// If it hasn't started, see if the user gave some slots and start from that step
if(!sampleHelper.started){
sampleHelper.determineStep(name, category, event);
}
sampleHelper.started = true;
// Did they provide all the necessary info?
if(sampleHelper.completed()){
// Handles reading out the menu, etc
return sampleHelper.updateSheet(response);
}
);
and here's what updateSheet looks
SampleHelper.prototype.updateSheet = function(resp){
var name = this.observance[0].steps[0].value;
var category = this.observance[0].steps[1].value;
var event = this.observance[0].steps[2].value;
console.log("about to auth.");
return authorize(JSON.stringify(this.access_token))
.then(function(auth){
console.log("passed auth");
return getColumns(auth, name, category).then(function(){
console.log("get columns");
return updateSheet(auth,name,category,event).then(function(){
console.log("finished updating");
return resp.say("Successfully logged for " + name + " a " + category + " of " + event).send();
});
}).catch(function(err){
console.log("failed columns");
return resp.say(err).send();
});
})
.catch(function (err) {
console.log("Auth err: ", err);
return resp.say("There was an error authenticating. Please check your Alexa app for how to reconnect your google account.").send();
});
};
my local terminal ouput:
AWS output using the exact same JSON for the request:
My node versions are both 6.10 and I have both alexa-app-server/my app using alexa-app: "^4.0.0"
local response:
{
"version": "1.0",
"response": {
"directives": [],
"shouldEndSession": true,
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>Successfully logged</speak>"
}
},
"sessionAttributes": {},
"dummy": "text"
}
Lambda's empty:
{
"version": "1.0",
"response": {
"directives": [],
"shouldEndSession": true
},
"sessionAttributes": {}
}
So with help of an awesome friend at PSU I figured it out.
I was actually returning my code and when Lambda sees that return it kills the function. When running on your local machine, it'll return, but not kill the process and therefore the rest of the code will still run.
To solve this, I wrapped everything in a promise and then returned that with a .then()
// Did they provide all the necessary info?
if(sampleHelper.completed()){
// Handles reading out the menu, etc
return sampleHelper.updateSheet(response).then(function(data){
return response.say("Successfully logged for " + sampleHelper.getName() + " a " + sampleHelper.getCategory() + " of " + sampleHelper.getEvent()).send();
}).catch(function(err){
console.log(err);
return response.say("error").send();
});
}
and the updateSheet:
return new Promise(function(resolve, reject) {
authorize(JSON.stringify(access_token))
.then(function (auth) {
console.log("passed auth");
getColumns(auth, name, category).then(function () {
console.log("get columns");
updateSheet(auth, name, category, event).then(function () {
console.log(new Date().getTime());
resolve("worked");
});
}).catch(function (err) {
console.log("failed columns");
throw "Failed columns";
// return resp.say(err).send();
});
})
.catch(function (err) {
throw err;
console.log("Auth err: ", err);
return resp.say("There was an error authenticating. Please check your Alexa app for how to reconnect your google account.").send();
});
});

Issue with Promise

I got a small problem with my function below. The Promise.map doesn't wait for Folder.create to be finished and iterate through the next value.
Promise.map(name, function(na){
return fs.stat(na.url, function(err, stats){
if (typeof stats === 'undefined'){
console.log("file doesn't exist");
return Folder.create(na).then(function(fd){
return mkdirp(root + product.url).then(function(){
console.log("Folder Created");
return null;
});
}, function(err){
console.log(err);
return reject({message: "Error when creating the folder"});
});
}
});
}).then(function(){
console.log('Iteration Done');
return resolve({message: "Folder Created!"});
});
// I GOT :
//file doesn't exist
//file doesn't exist
//file doesn't exist
//Iteration Done
//file doesn't exist
//file doesn't exist
//file doesn't exist
//Iteration Done
//Folder Created
//Folder Created
//Folder Created
//Folder Created
//Folder Created
//Folder Created
There are a couple issues here:
Promise.map() runs the operations for each array element in parallel, not serially. If you want them run serially, you can pass {concurrency: 1} as an option to Promise.map() or use Promise.mapSeries().
fs.stat() does not return a promise so your main callback to Promise.map() isn't returning a promise so the whole Promise.map() infrastructure does not know how to wait for any of your results. You can promisify fs.stat() to solve that issue.
You appear to be using an anti-pattern with your resolve() and reject() calls in here. You don't show the outer definition where those come from, but you should be just using the promise returned from Promise.map() rather than doing that.
Here's how they can successfully be run in parallel:
var fs = Promise.promisifyAll(require('fs'));
Promise.map(name, function(na){
return fs.statAsync(na.url).then(function(err, stats){
if (typeof stats === 'undefined'){
console.log("file doesn't exist");
return Folder.create(na).then(function(fd){
return mkdirp(root + product.url).then(function(){
console.log("Folder Created");
return null;
});
}, function(err){
console.log(err);
return Promise.reject({message: "Error when creating the folder"});
});
}
});
}).then(function(){
console.log('Iteration Done');
return ({message: "Folder Created!"});
});
If you wanted to run your operations serially with Bluebird, you could pass {concurrency: 1} to Promise.map():
Promise.map(name, fn, {concurrency: 1}).then(...);
Or use:
Promise.mapSeries(name, fn).then(...)
fs.stat is a callback type function and thus, does not return a Promise. You should modify your code to be something like this
// This might not work directly. I haven't tried to run it
Promise.map(name, function(na) {
return new Promise(function(resolve, reject) {
fs.stat(na.url, function(err, stats) {
if (typeof stats === 'undefined') {
console.log("file doesn't exist");
Folder.create(na).then(function(fd) {
return mkdirp(root + product.url);
}).then(function() {
console.log("Folder Created");
resolve();
}).catch(function(err) {
console.log(err);
reject({
message: "Error when creating the folder"
});
});
} else {
resolve();
}
});
});
}).then(function() {
console.log('Iteration Done');
return {
message: "Folder Created!"
};
});

can't execute query.find() in my cloud code

I have a cloud code that fetch data from 'Core' & HTTP API and do some logic on it. Now I want to send push notification based on the result but the code doesn't even getting executed here is a snippet of code
.then(function(result) {
for (var i = 0; i < queryObjects.length; i++) {
var object = queryObjects[i];
console.log('This will loop for '+queryObjects.length+' times');
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo('installationID',object.get('installationID'));
pushQuery.equalTo('deviceType','ios');
Parse.Push.send({
where: pushQuery,
data: {
alert: "When do we take to outer space",
badge: "Increment"
}
}, {
success: function() {
console.log("Push was successful");
},
error: function(error) {
console.error(error);
}
});
}
Even If I tried to execute query.find() nothing happened
.then(function(result) {
for (var i = 0; i < queryObjects.length; i++) {
var object = queryObjects[i];
console.log('This will loop for '+queryObjects.length+' times');
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo('installationID',object.get('installationID'));
pushQuery.equalTo('deviceType','ios');
pushQuery.find({
success:function(list) {
console.log("Query Data: "+list);
},
error: function(error) {
console.log("Error: " + error.code + " " + error.message);
}
});
}
This is because of the asynchronous nature of Push.Send function. You are calling it multiple times in a loop but you do not wait for any of those calls to finish before returning from the .then block. You need to know that when a Pasre asynchronous function returns, it is not necessarily finished. You need to wait on its Promise to be fulfilled just to make sure it has completed.
You can change your code to make sure that you call Parse.Push function only once (in your Installation query, use containedIn constraint on the array of your installationIDs you build in the loop and call Parse.Push only once after the loop and make sure to return its Promise.
The other solution is that for each time you call a Parse.Push function in the loop, you need to push them in an array of promises and then wait for all of them to finish using Parse.Promise.when(promises);. The documentation is very clear on how to wait on Promises in parallel.

Parse : Trying multiple query in a function of Parse Cloud code. Second query doesn't seem to work

I am trying to run multiple queries inside Parse cloud function. Second query doesnt get
executed
Parse.Cloud.beforeSave("PhoneNumbers", function(request, response) {
// Check if the same phone number for the same user exists
var PhoneNumbersObject = Parse.Object.extend('PhoneNumbers');
var duplicationQuery = new Parse.Query(PhoneNumbersObject);
duplicationQuery.equalTo('user', Parse.User.current());
duplicationQuery.equalTo('phoneNumber', request.object.get("phoneNumber"));
duplicationQuery.count({
success: function(count) {
if (count > 0) {
response.error("This number is already stored");
}
},
error: function(error) {
response.error("Error " + error.code + " : " + error.message + " when storing phone number");
}
});
var firstPhoneNumberQuery = new Parse.Query(PhoneNumbersObject);
firstPhoneNumberQuery.equalTo('user', Parse.User.current());
firstPhoneNumberQuery.find({ // <<<<< find doesn't work
success: function(results) {
if ( results.length == 0 ) {
console.log("User's first telephone number"); // <<< Never reaches here
request.object.set("primary", true);
} else {
console.log("Hello"); // <<< Never reaches here
}
},
error: function(error) {
console.log("Bye");
response.error("Query failed. Error = " + error.message);
}
});
response.success();
});
The issue is that queries are async. You're not waiting for the query to finish before calling response.success().
Think of your call to firstPhoneNumberQuery.find() like putting eggs on to boil, the success and error blocks are what you'll do when it is done.
The call to response.success() is like telling the cleaners you are done and they can toss whatever is still "cooking".
Use promises to avoid this issue, as well as moving the response.success() call inside your query's success handler:
duplicationQuery.count({
// ... success / error as above
}).then(function() {
var firstPhoneNumberQuery = new Parse.Query(PhoneNumbersObject);
firstPhoneNumberQuery.equalTo('user', Parse.User.current());
// return the promise so we can keep chaining
return firstPhoneNumberQuery.find();
}).then(function(results) {
// ... success for find
// then call success() here
response.success();
}, function(error) {
// ... error block for find
});
As you can see, you can combine as many then() blocks as you need.
Learn more about promises and chaining here:
https://parse.com/docs/js_guide#promises

Cloud code with many deletes in loop, but response.success finishes first on parse.com

I have a query, and they query may return many items.
I can go through all of them and destroy them.
The problem is since destroy is Async, the response.success(); part is executed before all the destroys are executed, so not all items are really deleted.
How can I make it wait until the loop is done and then only response.success();
Thanks.
garageQuery2.find({
success: function(results) {
alert("Successfully retrieved " + results.length + " garages to delete.");
// Do something with the returned Parse.Object values
for (var i = 0; i < results.length; i++) {
var object = results[i];
object.destroy({
success: function(myObject) {
// The object was deleted from the Parse Cloud.
},
error: function(myObject, error) {
// The delete failed.
// error is a Parse.Error with an error code and description.
}
});
}
response.success();
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
Try to work with Promises
This code is based on this: https://www.parse.com/docs/js_guide#promises-series
garageQuery2.find().then(function(results) {
// Create a trivial resolved promise as a base case.
var promiseSeries = Parse.Promise.as();
// the "_" is given by declaring "var _ = require('underscore');" on the top of your module. You'll use Underscore JS library, natively supported by parse.com
_.each(results, function(objToKill) {
// For each item, extend the promise with a function to delete it.
promiseSeries = promiseSeries.then(function() {
// Return a promise that will be resolved when the delete is finished.
return objToKill.destroy();
});
});
return promiseSeries;
}).then(function() {
// All items have been deleted, return to the client
response.success();
});
Hope it helps

Resources