Parse.com: Update of user table is not working - parse-platform

I have defined a cloud function to set custom column in User table. I have 6 results returned for my query but update of field only happens for 3 rows, I could not understand what's wrong with the code below,
Parse.Cloud.define("updateSaturdayAbsentWeeks", function(request, response) {
// User master key so that we can update all users
Parse.Cloud.useMasterKey();
// Tables to Query
var query = new Parse.Query(Parse.User);
// We want only players who are absent on Saturdays
query.equalTo("isSaturdayAbsent", true);
query.find({
success: function(results) {
console.error('updateSaturdayAbsentWeeks, Saturday absent players count ' + results.length);
for (var i = 0; i < results.length; i++) {
var absentUser = results[i];
var absentWeeks = absentUser.get('saturdayAbsentWeeks') - 1;
absentUser.set("saturdayAbsentWeeks", absentWeeks);
absentUser.save();
console.error('updateSaturdayAbsentWeeks, absentWeeks for user name = ' + absentUser.get('username') + ', is = ' + absentWeeks)
}
// All done
response.success("updateSaturdayAbsentWeeks finished successfully");
},
error: function() {
console.error("runSaturdayExpense, lookUp Failed - Each player enjoyed the game on Saturday ");
response.error("updateSaturdayAbsentWeeks failed");
}
});
});
After the query I can see it returned 6 records but in the for loop it only updates 3 records only and does not do anything to other three records and no errors returned.
Any pointers to understand why all 6 records are not getting updated would be greatly appreciated.
Thanks

This has to do with the fact that the save() function is asynchronous. The proper way to do this is using saveAll().
query.find({
success: function(results) {
var saveThese = [];
for (var i = 0; i < results.length; i++) {
var absentUser = results[i];
var absentWeeks = absentUser.get('saturdayAbsentWeeks') - 1;
absentUser.set("saturdayAbsentWeeks", absentWeeks);
saveThese.push(absentUser);
}
Parse.Object.saveAll(saveThese, {
success: function (list) {
response.success("updateSaturdayAbsentWeeks finished successfully");
},
error: function (error) {
response.error("did not save all the items");
}
});
},
error: function() {
response.error("updateSaturdayAbsentWeeks failed");
}
});

Related

Dragula not sending AJAX request

I am using the following code to sort the rows of a table based on Ids. I am using Dragula for drag and drop functionality. The Sorted Ids is presented in the variable sortedIDs. The alert present within if(sortedIDs) is showing an alert, but no request is being sent using AJAX.
var container = document.getElementById('tb');
var rows = container.children;
var nodeListForEach = function (array, callback, scope) {
for (var i = 0; i < array.length; i++) {
callback.call(scope, i, array[i]);
}
};
var sortableTable = dragula([container]);
var pingu='';
sortableTable.on('dragend', function() {
nodeListForEach(rows, function (index, row) {
//alert(row.id);
pingu=pingu+','+row.id;
//alert(pingu);
// row.lastElementChild.textContent = index + 1;
// row.dataset.rowPosition = index + 1;
});
var sortedIDs=pingu;
pingu='';
// alert (sortedIDs);
if (sortedIDs) {
alert(sortedIDs);
$.ajax({
type: 'GET',
url: '<?php echo $site_url . 'index.php/API/p2376ghDSPOLWYBdhBT'?>',
data: 'lmqSPOEhyVt87H6tBYSfdreg=' + sortedIDs + '&hjhqweuty87685gh87GCfsc6HF=' + sbds98JWUDGHKJ98yujg,
success: function (tata) {
alert (tata);
if (tata == '1') {
$("#success").show();
$('#success').delay(2000).fadeOut('slow');
} else {
$("#failure").show();
$('#failure').delay(5000).fadeOut('slow');
}
}
});
} else {
//$('#ms').html('<option value="">Select Q level first</option>');
}
});
And when i am adding
error : function(jqXHR, textStatus, errorThrown){
}
for showing AJAX error, it starts throwing the alert too.
Any sort of help would be deeply appreciated.
Thanks
I solved the problem. I forgot to retrieve the value of an attribute and send it to the API.
var sbds98JWUDGHKJ98yujg = $('#p2JMopns3hfBubNNHJeer').val();

Get Data from parse.com Promises

I am trying to use parse.com promises to retrieve job data as well as user relation data associated with the job. I have a function that returns promises but not job data. How do I get the job & employee information from the returned promises?
Logically I want to:
1) Query Parse to get array of jobs
2) For each job, query Parse again to get the employee relation information
3) Create local object that contains job & employee details
4) Add each job object to local array
5) Load table with array of objects once all information has been retrieved from Parse
I can do steps 1-4 but I can't figure out how to wait until all information has been retrieved from Parse to refresh the local table.
function getJobPromises (){
var promises = [];
var Job = Parse.Object.extend("Job");
var query = new Parse.Query(Job);
query.equalTo("company", company);
query.notEqualTo("isDeleted", true);
query.limit(1000); // raise limit to max amount
query.find().then(function(results) {
// Create a trivial resolved promise as a base case.
var promise = Parse.Promise.as();
_.each(results, function(result) {
// For each item, extend the promise with a function to add it to the job array
promise = promise.then(function() {
// Return a promise that will be resolved when the job details have been added to the array
var object = result;
promises.push(getEmployeeName(object));
allJobDataArray = promises;
});
});
return Parse.Promise.when(promises);
}).then(function() {
// Every job has been retrieved
console.log("All items have been returned. Refresh table...");
console.log(allJobDataArray);
});
}
The function that does the relational query to get the users associated with the job
function getEmployeeName(jobObject) {
var employeeNameArray = [];
//Query to get array of employees for the passed in job
var rQuery = jobObject.relation("employee");
return rQuery.query().find({
success: function(employees){
//Get employees full name for each job
for (var i = 0; i < employees.length; i++) {
var objEmployee = employees[i];
var fullName = objEmployee.get("fullName");
employeeNameArray.push(fullName);
console.log(employeeNameArray);
}
},
error: function(error){
response.error(error);
}
});
}
Update
It is now working thanks to #eduardo
I have a public array to hold the job objects.
var jobObjectsArray = [];
In the getEmployeeName function I am creating the job objects and adding them to that array
function getJobPromises (){
var promises = [];
var Job = Parse.Object.extend("Job");
var query = new Parse.Query(Job);
query.equalTo("company", company);
query.notEqualTo("isDeleted", true);
query.limit(1000); // raise limit to max amount
query.find().then(function(results) {
_.each(results, function(result) {
promises.push(getEmployeeName(result));
});
return Parse.Promise.when(promises);
}).then(function(allJobDataArray) {
// allJobDataArray should be actually an Array of Array
console.log(jobObjectsArray);
refreshTable();
});
}
function getEmployeeName(jobObject) {
var employeeNameArray = [];
//Query to get array of employees for the passed in job
var rQuery = jobObject.relation("employee");
return new Promise(
function(resolve, reject) {
rQuery.query().find({
success: function(employees){
//Get employees full name for each job
for (var i = 0; i < employees.length; i++) {
var objEmployee = employees[i];
var fullName = objEmployee.get("fullName");
employeeNameArray.push(fullName);
var objAllJobs = new Object();
objAllJobs["jobId"] = jobObject.id;
objAllJobs["location"] = jobObject.get("location");
objAllJobs["startTime"] = jobObject.get("startTime");
objAllJobs["employee"] = employeeNameArray;
jobObjectsArray.push(objAllJobs);
}
console.log(employeeNameArray);
resolve(employeeNameArray);
},
error: function(error){
reject(error);
}
});
}
);
There was a few incorrect uses of the promise concept. I will go through them, but first here is the final code:
function getJobPromises (){
var promises = [];
var Job = Parse.Object.extend("Job");
var query = new Parse.Query(Job);
query.equalTo("company", company);
query.notEqualTo("isDeleted", true);
query.limit(1000); // raise limit to max amount
query.find().then(function(results) {
_.each(results, function(result) {
promises.push(getEmployeeName(result));
});
return Parse.Promise.when(promises);
}).then(function(allJobDataArray) {
// allJobDataArray should be actually an Array of Array
console.dir(allJobDataArray);
console.log(allJobDataArray[0]);
});
}
function getEmployeeName(jobObject) {
var employeeNameArray = [];
//Query to get array of employees for the passed in job
var rQuery = jobObject.relation("employee");
return rQuery.query().find({
success: function(employees){
//Get employees full name for each job
for (var i = 0; i < employees.length; i++) {
var objEmployee = employees[i];
var fullName = objEmployee.get("fullName");
employeeNameArray.push(fullName);
}
console.log(employeeNameArray);
return employeeNameArray;
},
error: function(error){
response.error(error);
}
});
}
"Parse.Promise.as()" should be used only if you have a value that you want to return as a promise. Something like:
Parse.Promise.as("my value").then(function(foo) {
console.log(foo) // "my value"
});
So if your "getEmployeeName" function is returning a promise, which means that this "rQuery.query().find" returns a promise, you don't have to create a new promise or use the "Parse.Promise.as()", it is already a promise and you can push it to the promises array.
Another problem was that you were not return anything in the "getEmployeeName" method callback. Take a look into my version, I'm returning "employeeNameArray".
My version will only work if this "rQuery.query().find" method returns a promise. If that is not the case, you can create a new promise using its callbacks like this:
function getEmployeeName(jobObject) {
var employeeNameArray = [];
//Query to get array of employees for the passed in job
var rQuery = jobObject.relation("employee");
return new Promise(
function(resolve, reject) {
rQuery.query().find({
success: function(employees){
//Get employees full name for each job
for (var i = 0; i < employees.length; i++) {
var objEmployee = employees[i];
var fullName = objEmployee.get("fullName");
employeeNameArray.push(fullName);
}
console.log(employeeNameArray);
resolve(employeeNameArray);
},
error: function(error){
reject(error);
}
});
}
);
}
Please notice this "new Promise()" depends on the browser support of Promise, I don't know if Parse has an equivalent. Anyways you can use it with a polyfill that implements the necessary code if the browser has no support.
More about standard promises: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Polyfill: https://github.com/jakearchibald/es6-promise/
Hope this helps.

Recursive Query to get more than 1000 results outside Parse.cloud impossible?

I'm in need to fetch over 1000 elements from a Class.
So I tried following advices on this topic, but something is not working correctly, and already spent the whole day to find a solution.
Parse.Cloud.define("getFollow", function(request, response) {
var following = [];
var user = request.params.user;
user.fetch().then(function(result) {
if (!result.get('following')) {
following = getFollowing({
'user': user
});
}
}).then(function() {
response.success(following);
}, function(error) {
response.error(error);
});
});
function getFollowing(request) {
var count = 0;
var skip = request.skip || 0;
var limit = 1000;
var following = request.following || [];
var Follow = Parse.Object.extend('follow');
var query = new Parse.Query(Follow);
query.limit(limit);
query.ascending('objectId');
query.skip(skip * limit);
query.equalTo('followers', request.user);
query.find().then(function(results) {
skip+= 1;
count = results.length;
/* I can't see any DEBUG, seems nothing is queried */
console.log('[DEBUG] Check <count>: ' + count);
return Parse.Promise.when(results.map(function(result) {
following.push(result.get('followed'));
}));
}).then(function() {
if(count >= limit) {
following = getFollowingUsers({
'user': request.user,
'skip': skip,
'following': following
});
}
}).then(function() {
return following;
}, function(error) {
return error;
});
}
I tried many variant of this code, trying to return the very first result of the query, rather than a collection. I also tried to remove all contraints, but even so, my query seems not to be run.
I also tried to use a Cloud.code function to make this recursively using only Parse.Cloud, but if I do that, I'm having a message Too many recursive calls into Cloud Code
What did I do wrong with this logic ?

Error Message- Failed with: success/error was not called

Parse.Cloud.job("JobSchedule", function(request, response) {
var Group = Parse.Object.extend("Group");
var query = new Parse.Query(Group);
query.equalTo("JobScheduled", true);
query.find({
success: function(results) {
for (var i = 0; i < results.length; ++i) {
var created = new Date(results[i].createdAt);
var current = new Date();
var timeDiff = Math.abs(current.getTime() - created.getTime());
var horsDiff = timeDiff / (60 * 60 * 1000);
if (horsDiff >= parseInt(results[i].get("JobHours"))) {
results[i].set("JobScheduled", false);
results[i].set("GroupType", "Private");
results[i].set("JobHours", 0);
results[i].save();
var GroupMembers = Parse.Object.extend("GroupMembers");
var query1 = new Parse.Query(GroupMembers);
query1.equalTo("GroupId", results[i].id);
query1.find({
success: function(grpresults) {
for (var j = 0; j < grpresults.length; ++j) {
grpresults[j].set("GroupType", "Private");
grpresults[j].save();
}
},
error: function(error) {
response.error(error);
}
})
}
}
},
error: function(error) {
response.error(error);
}
});
});
Script is running properly(it updates the values as defined). But in parse log it shown as Failed with: success/error was not called. Please suggest me over this issue
You simply never call response.success() or response.error(), and you should always call at least one of those.
You should really be storing all of the promises returned from your queries and saves and waiting until all of them are complete and then calling success or error based on the result from those promises.

Adding contraints to a column on Parse Data

I'm saving some objects into tables on my Parse Data. But I need to add a constraint or make sure that the data i'm trying to insert is unique. I'm using something like the following code. But i want to guarantee that the eventId (that I'm getting from facebook API) is unique in my tables, so i don't have any redundant information. What is the best way to make it work?
var Event = Parse.Object.extend("Event");
var event = new Event();
event.set("eventId", id);
event.set("eventName", name);
event.save(null, {
success: function(event) {
console.log('New object created with objectId: ' + event.eventId);
},
error: function(event, error) {
console.log('Failed to create new object, with error code: ' + error.message);
}
});
Update:
I'm calling it inside a httpRequest. The following is pretty much what I have and I cant figure out just how to call a beforeSave inside it.
Parse.Cloud.define("hello", function(request, response) {
var query = new Parse.Query("Location");
query.find({
success: function(results) {
console.log(results);
var totalResults = results.length;
var completedResults = 0;
var completion = function() {
response.success("Finished");
};
for (var i = 0; i < totalResults; ++i){
locationId = results[i].get("locationFbId");
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/'+locationId+'/events?access_token='+accessToken,
success: function(httpResponse) {
console.log(httpResponse.data);
console.log("dsa"+locationId);
for (var key in httpResponse.data) {
var obj = httpResponse.data[key];
for (var prop in obj) {
var eventObj = obj[prop];
if (typeof(eventObj) === 'object' && eventObj.hasOwnProperty("id")) {
var FbEvent = Parse.Object.extend("FbEvent");
var fbEvent = new FbEvent();
fbEvent.set("startDate",eventObj["start_time"]);
fbEvent.set("locationFbId", locationId);
fbEvent.set("fbEventId", eventObj["id"]);
fbEvent.set("fbEventName", eventObj["name"]);
Parse.Cloud.beforeSave("FbEvent", function(request, response) {
var query = new Parse.Query("FbEvent");
query.equalTo("fbEventId", request.params.fbEventId);
query.count({
success: function(number) {
if(number>0){
response.error("Event not unique");
} else {
response.success();
}
},
error: function(error) {
response.error(error);
}
});
});
}
}
}
completedResults++;
if (completedResults == totalResults) {
completion();
}
},
error:function(httpResponse){
completedResults++;
if (completedResults == totalResults)
response.error("Failed to login");
}
});
}
},
error: function() {
response.error("Failed on getting locationId");
}
});
});
So this is occurring in Cloud Code correct? (Im assuming since this is Javascript)
What you could do is create a function that occurs before each "Event" object is saved and run a query to make sure that the event is unique (query based off of "eventId" key, not objectId since the id comes from Facebook). If the event is unique, return response.success(), otherwise return response.error("Event not unique")
EX:
Parse.Cloud.beforeSave("Event", function(request, response) {
if(request.object.dirty("eventId")){
var query = var new Parse.Query("Event");
query.equalTo("eventId", request.object.eventId);
query.count({
success: function(number) {
if(number>0){
response.error("Event not unique");
} else {
response.success();
}
},
error: function(error) {
response.error(error);
}
});
} else {
response.success();
}
});
Parse.Cloud.define("hello", function(request, response) {
var query = new Parse.Query("Location");
query.find({
success: function(results) {
console.log(results);
var totalResults = results.length;
var completedResults = 0;
var completion = function() {
response.success("Finished");
};
for (var i = 0; i < totalResults; ++i){
locationId = results[i].get("locationFbId");
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/'+locationId+'/events?access_token='+accessToken,
success: function(httpResponse) {
console.log(httpResponse.data);
console.log("dsa"+locationId);
for (var key in httpResponse.data) {
var obj = httpResponse.data[key];
for (var prop in obj) {
var eventObj = obj[prop];
if (typeof(eventObj) === 'object' && eventObj.hasOwnProperty("id")) {
var FbEvent = Parse.Object.extend("FbEvent");
var fbEvent = new FbEvent();
fbEvent.set("startDate",eventObj["start_time"]);
fbEvent.set("locationFbId", locationId);
fbEvent.set("fbEventId", eventObj["id"]);
fbEvent.set("fbEventName", eventObj["name"]);
// Our beforeSave function is automatically called here when we save it (this will happen every time we save, so we could even upgrade our method as shown in its definition above)
fbEvent.save(null, {
success: function(event) {
console.log('New object created with objectId: ' + event.eventId);
},
error: function(event, error) {
console.log('Failed to create new object, with error code: ' + error.message);
}
});
}
}
}
completedResults++;
if (completedResults == totalResults) {
completion();
}
},
error:function(httpResponse){
completedResults++;
if (completedResults == totalResults)
response.error("Failed to login");
}
});
}
},
error: function() {
response.error("Failed on getting locationId");
}
});
});
This can also be accomplished before ever calling the save by querying and only saving if the query returns with a number == 0.
Summary: For those joining later, what we are doing here is checking to see if an object is unique (this time based on key eventId, but we could use any key) by overriding Parse's beforeSave function. This does mean that when we save our objects (for the first time) we need to be extra sure we have logic to handle the error that the object is not unique. Otherwise this could break the user experience (you should have error handling that doesn't break the user experience anyway though).

Resources