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

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.

Related

jQuery deferred promise progress notification

I've been playing with promises and trying to build some sort of progress notification.
The code is executing all functions in the right order, but the progress updates execute just before the resolve as opposed to when they actually happen.
Can anyone point out what I'm doing wrong?
function start(x) {
console.log("Start: " + x);
var promise = process(x);
console.log("promise returned");
promise.then(function(data) {
console.log("Completed: " + data);
}, function(data) {
console.log("Cancelled: " + data);
}, function(data) {
console.log("In Progress: " + data);
});
}
function process(x) {
var deferred = $.Deferred();
var promise = deferred.promise();
// process asynchronously
setTimeout(function() {
for (var i=0 ; i<x ; i++) {
sleep(1000);
deferred.notify(i);
}
if (x % 2 === 0) {
deferred.reject(x);
} else {
deferred.resolve(x);
}
}, 0);
return promise;
}
function sleep(sleepDuration) {
var now = new Date().getTime();
while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
}
start(3);
Fiddle here:
https://jsfiddle.net/n86mr9tL/
A delay timer implemented with while(), will "block" - ie hog the processor.
Blocking not only prevents other javascript from running but also inhibits reliable refreshing of the browser screen including the console. So whereas those deferred.notify(i) and console.log("In Progress: " + data) statements are firing, the console isn't refreshed until the processor becomes free to do so.
Unsurprisingly, the solution lies in not using while().
Fortunately, javascript imcludes two built-in methods window.setTimeout() and window.setInterval(), which are conceptually different from a while() idler but fulfil the same role .... without blocking.
window.setInterval(fn, t) fires function fn every t milliseconds,
window.setTimeout(fn, t) fires function fn once, after t milliseconds.
Both methods return an opaque reference, which allows them to be cancelled.
In the code below, start() is unmodified, process() is heavily modified and sleep() has disappeared.
process() now does the following :
creates a jQuery Deferred and returns a promise derived from it,
establises a setInterval() of 1000 milliseconds (1 second), whose function :
keeps count of how many times it has been called,
calls deferred.notify() every second until the counter i reaches the specified maximum x,
when the specified maximum is reached :
the interval, which would otherwise silently tick away ad infinitum, is cleared,
deferred.resolve() or deferred.reject() are called to settle the Deferred (and its promise),
function start(x) {
console.log("Start: " + x);
process(x).then(function(data) {
console.log("Completed: " + data);
}, function(data) {
console.log("Cancelled: " + data);
}, function(data) {
console.log("In Progress: " + data);
});
}
function process(x) {
return $.Deferred(function(dfd) {
var i = 1;
var intervalRef = setInterval(function() {
if(i < x) {
dfd.notify(i++);
} else {
clearInterval(intervalRef);
dfd[(x % 2 === 0)?'reject':'resolve'](x);
}
}, 1000);
}).promise();
}
console.clear();
start(3);
Updated fiddle

Parse Query equalTo not Working

I'm trying to simply query my database filtering results with a parameter (named: "lesson") I've just obtained from another query.
The problem is that when I try to print with an "alert" command lesson's value it says: undefined.
It is wierd that when I put "lesson" inside a tuple's field it works.
In particular line
obj.set("student", lesson);
added just for debugging purpose, actually writes a consistent value into the table.
This is the whole code:
Parse.Cloud.job("checkingTwoTables", function(request, response) {
Parse.Cloud.useMasterKey();
var stud,lesson;
//select first student of the list and check for his enters
var wholeTable = new Parse.Query("enter");
wholeTable.find({
success: function(result) {
if(result.length != 0)
{
//pick student name and lesson we're interested in
stud = result[0].get("student");
lesson = result[0].get("lesson");
}
else {}
},
error: function(error) {
console.log("failed");
}
});
alert("lesson value:" + lesson);
var selectionQuery = new Parse.Query("enter");
selectionQuery.equalTo("lesson", "cns");
selectionQuery.find({
success: function(results) {
for (var i = 0; i < results.length; i++)
{
var obj = results[i];
obj.set("raggiunto", 77);
obj.set("student", lesson); // <<-------HERE IS THE ISSUE
obj.save(null,{
success: function (object) {
response.success(object);
},
error: function (object, error) {
response.error(error);
}
});
}
},
error: function(error) {
console.log("failed");
}
}); //code continues...
You are having this exact issue.
.find() is making a request with the server. You cannot guarantee when it would finish thus you cannot guarantee that your second query will run after the first one completes. Therefore, when your second query runs, the value of lesson may still have not been retrieved yet by the first query, hence the "undefined".
The solution would be to move the second query inside the success block of the first query.

Parse Cloud: Query not running in exported function from save() callback

I'm using Parse to represent the state of a beer keg (among other things). I'd like to check the user's notifications, stored in a "Notifications" table, to see if they'd like to receive a notification when the keg is filled.
I have all of the logic for setting the user's notification settings as well as sending notifications in cloud/notifications.js. All of the logic for updating the keg is in cloud/beer.js. I created an exported function called "sendKegRefillNotification" which performs a query.find() on the Notifications table and gets called from beer.js.
The problem is that it doesn't seem to be executing query.find() when I call the function from beer.js, however when I call the same function from a job within notifications.js, it works just fine.
main.js:
require("cloud/beer.js");
require("cloud/notifications.js");
beer.js:
var notify = require("cloud/notifications.js");
var Keg = Parse.Object.extend("Keg");
var fillKeg = function(beerName) {
var promise = new Parse.Promise();
var keg = new Keg();
keg.set("beerName", beerName)
keg.set("kickedReports", []);
keg.save(null, { useMasterKey: true }).then(function(keg) {
console.log("Keg updated to " + beerName + ".");
promise.resolve(keg);
notify.sendKegRefillNotification(keg);
},
function(keg, error) {
promise.reject(error);
});
return promise;
}
Parse.Cloud.define("beerFillKeg", function(request, response) {
var beerName = request.params.name;
if (!beerName) {
response.error("No beer was specified.");
return;
}
if (!util.isUserAdmin(request.user)) {
response.error("User does not have permission to update the keg.");
return;
}
fillKeg(beerName).then(function(keg) {
kegResponse(keg).then(function(result) {
response.success(result);
});
},
function(error) {
response.error(error);
});
});
function kegResponse(keg) {
var promise = new Parse.Promise();
var result = {
id: keg.id,
beer: {
name: keg.get("beerName")
},
filled: keg.createdAt,
kickedReports: []
};
var kickedReports = keg.get("kickedReports");
if (!kickedReports || kickedReports.length == 0) {
promise.resolve(result);
} else {
util.findUsers(kickedReports).then(function(users) {
result.kickedReports = util.infoForUsers(users);
promise.resolve(result);
}, function(users, error) {
console.log(error);
promise.resolve(result);
});
}
return promise;
}
notifications.js:
var Keg = Parse.Object.extend("Keg");
var Notification = Parse.Object.extend("Notifications");
exports.sendKegRefillNotification = function(keg) {
var beerName = keg.get("beerName");
console.log("Sending notifications that keg is refilled to '" + beerName + "'.");
var promise = new Parse.Promise();
var query = new Parse.Query(Notification);
query.include("user");
query.equalTo("keg_filled", true);
query.find({ useMasterKey: true }).then(function(notifications) {
console.log("Found notifications!");
promise.resolve("Found notifications!");
},
function(notifications, error) {
console.error("No notifications");
console.error(error);
promise.reject(error);
});
return promise;
}
Parse.Cloud.job("beerSendRefillNotification", function(request, status) {
var query = new Parse.Query(Keg);
query.descending("createdAt");
query.first().then(function(keg) {
if (!keg) {
status.error("No keg");
return;
}
exports.sendKegRefillNotification(keg);
},
function(keg, error) {
response.error(error);
});
});
When I run the job "beerSendRefillNotification" from the Parse dashboard, I can tell that query.find() is getting called because it prints "Found notifications!":
E2015-02-23T06:59:49.006Z]v1564 Ran job beerSendRefillNotification with:
Input: {}
Result: success/error was not called
I2015-02-23T06:59:49.055Z]false
I2015-02-23T06:59:49.190Z]Sending notifications that keg is refilled to 'test'.
I2015-02-23T06:59:49.243Z]Found notifications!
However, when I call the cloud function "beerFillKeg", it isn't because it's not printing "Found notifications!" or "No notifications":
I2015-02-23T07:00:17.414Z]v1564 Ran cloud function beerFillKeg for user HKePOEWZvC with:
Input: {"name":"Duff"}
Result: {"beer":{"name":"Duff"},"filled":{"__type":"Date","iso":"2015-02-23T07:00:17.485Z"},"id":"olLXh0F54E","kickedReports":[]}
I2015-02-23T07:00:17.438Z]false
I2015-02-23T07:00:17.523Z]Keg updated to Duff.
I2015-02-23T07:00:17.525Z]Sending notifications that keg is refilled to 'Duff'.
I finally understand it. In sendKegRefillNotification, you're calling query.find({...}), then returning an object. That find is asynchronous, and you're doing nothing to wait for the result. I think you need to return the find function call, rather than an object you set within that method.
In other words, you're running along, leaving some async running code behind you.
Edit: I understand what you tried to do. It sort of makes sense. You defined a promise, and thought the caller would wait for the promise. The problem is, the promise is defined in an asynchronous block. It doesn't yet have any meaning at the moment the caller gets it.
It looks like Parse doesn't allow you to run a query from inside a callback from save(). When I moved "notify.sendKegRefillNotification(keg);" to outside of the callback, it worked.
var fillKeg = function(beerName) {
var promise = new Parse.Promise();
var keg = new Keg();
keg.set("beerName", beerName)
keg.set("kickedReports", []);
keg.save(null, { useMasterKey: true }).then(function(keg) {
console.log("Keg updated to " + beerName + ".");
console.log("Send notifications.");
promise.resolve(keg);
},
function(keg, error) {
promise.reject(error);
});
notify.sendKegRefillNotification(keg); // Now this works
return promise;
}
Can anyone shed some more light on why this worked?

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