parse background job each() does not go through all records? - parse-platform

I wrote a cloud job to insert a lowercase version of a user's first name and last name in the user object so that I can perform a search from my client app.
When I did run this job on a dev parse app that had like 40 users it worked great.
When I did run this on my production app however it did not update all of my records. I have a few thousands users at the moment and I was expecting this cloud job to take care of all of them as explained here:
http://blog.parse.com/2013/05/13/launch-and-iterate-parse-data-migrations/
" The new each method on Parse.Query objects allows you to do just that. Even if you have tens of thousands of objects or more in a collection, it will return each one of them, giving you an opportunity to modify them as you see fit."
So then my question is why does this function leave behind over half of my database? It only worked on a bunch of users, maybe a few hundred.
How can I make this function affect my WHOLE DATASET in the User table?
Parse.Cloud.job("migration1", function(request, status) {
// Set up to modify user data
Parse.Cloud.useMasterKey();
// Query for all users
var query = new Parse.Query(Parse.User);
query.each(function(user) {
// Set and save the change
var firstname = user.get("firstname");
if(firstname) {
user.set("searchfirstname", firstname.toLowerCase());
} else {
user.set("searchfirstname", "");
}
var lastname = user.get("lastname");
if(lastname) {
user.set("searchlastname", lastname.toLowerCase());
} else {
user.set("searchlastname", "");
}
return user.save();
}).then(function() {
// Set the job's success status
status.success("search migration completed successfully.");
}, function(error) {
// Set the job's error status
status.error("Uh oh, something went wrong with search migration");
});
});
EDIT:
Ok so when I look at the error logs I see this:
E2014-10-18T15:48:49.984Z] v63: Ran job searchMigration with:
Input: {}
Failed with: TypeError: Cannot call method 'toLowerCase' of undefined
I tried to check for undefined in any way I could think of and I still get the same problem.
What I tried to check for undefined is this:
if(lastname === undefined || lastname === void 0 || typeof lastname == 'undefined') ...
I still get the toLowerCase of undefined error and I think that is why the job does not affect all of my user table since it stops...
Any suggestions?

So, I finally figured out why the job did not go through all the records but it would stop after a few records "randomly"...
I had an AfterSave hook for the user which was triggered at each iteration of the above job...
In that after save it would generate an error at times and make the Job fail.
So, for some reason I thought the after save hook would have not been triggered by a save done on the user while inside of a Job.
That's it. Now it all works.

Related

Parse save() from the client gets changes done in beforeSave?

Using parse from an Ios/Android app, I create a new object of my class "Tomato" and call save() or saveInBackground(...).
In this class "Tomato" beforeSave hook, I initialise some fields with custom values.
My question is, are those values available in the client after the save is completed? Or do i need to fetch the object after save it?
You would need to fetch it again to get access to the values created in beforeSave (note that refresh is deprecated and Parse now wants you to use fetch):
https://parse.com/docs/ios/api/Classes/PFObject.html#//api/name/fetch:
You have the updated object in the save callback:
gameScore.save(null, {
success: function(object) {
// The object was saved successfully.
},
error: function(object, error) {
// The save failed.
// error is a Parse.Error with an error code and message.
}
});
Android
ParseObject gameScore = new ParseObject("GameScore");
gameScore.put("score", 1337);
gameScore.put("playerName", "Sean Plott");
gameScore.put("cheatMode", false);
gameScore.saveInBackground();
After this code runs, you will probably be wondering if anything
really happened. To make sure the data was saved, you can look at the
Data Browser in your app on Parse. You should see something like this:
objectId: "xWMyZ4YEGZ", score: 1337, playerName: "Sean Plott", cheatMode: false,
createdAt:"2011-06-10T18:33:42Z", updatedAt:"2011-06-10T18:33:42Z"
Source: https://parse.com/docs/android/guide#objects-saving-objects

Parse.com - object not found for update

I know this question has been asked several times, but I haven't find a fix yet.
What I did was create a class called Earthquake and a background job which download contents, create an array on Earthquake and then save it through Parse.Object.saveAll(...).
Here some code (note: actualEarthquake is an object of the "Earthquake" class)
actualEarthquake.set("updated",updated);
actualEarthquake.set("place",place);
actualEarthquake.set("type",type);
//Save it to array
earthquakes.push(actualEarthquake);
writeToLog(pid, "Item -> " + i);
}
Parse.Object.saveAll(earthquakes, {
success: function(earthquakes) {
status.success("Yayy it's working... maybe");
},
error: function(error) {
writeToLog(pid,"Error -> " + error.message);
status.error("Such error much crash");
}
});
When I run the background job everything works ok except the saveAll which catch and error: "object not found for update". I have already tried applying and ACL to each single object but nothing changed.
The strange thing is that I have already another app which have almost the same code and... it works!!
Add this before you make saveAll call:
Parse.Cloud.useMasterKey();

Calling Parse.Cloud.beforeSave() From custom web hooks

I started off cloning the cloud code example blog app. And in the controllers I have the basic REST crud operations. I tried adding the code here to my controller, as well as just directly in main.js:
Parse.Cloud.beforeSave(Parse.User, function(req, res)
{
for (var dirtyKey in req.object.dirtyKeys()) {
if (dirtyKey === "username" || dirtyKey === "email") {
res.error("User is not allowed to modify " + dirtyKey);
return;
}
}
res.success();
})
In my terminal, I am running parse develop [app] to update files as I change. And when I add the above code it does register a trigger.
Deploying recent changes...
Your changes are now live.
I2014-07-15T03:30:18.108Z]Deployed v63 with triggers:
_User:
before_save
Yet I am still able to, from the rest api using postman, able to update the username and email fields.
I suppose, that the real question should be, is that if I am building my app like this; do I still use these beforeSave() triggers like described? Or is it better to simply make those checks in the method (in this case, the User.update method i created) and validate everything there? Because I cant seem to get the triggers to actually run.
The issue is a common mistake with how for..in works in JavaScript with an array, in your code above dirtyKey will be populated with the index, what you want instead is:
for (var i in req.object.dirtyKeys()) {
var dirtyKey = req.object.dirtyKeys()[i];
if (dirtyKey === "username" || dirtyKey === "email") {
res.error("User is not allowed to modify " + dirtyKey);
return;
}
}

Significance of Reflection in AJAX-Based Applications

Ajax and Reflection
I am developing an ajax-based application and wondering, what role reflection plays or might play here?
Probably most importantly I am asking myself, if it would be a good approach to
handle all ajax responses through a single handler,
reflect or interpret the data or error
delegate further processing (e.g. where to inject the html) based upon the analysis.
Is this a budding procedure? What pros and cons come to mind?
Additional clearification
My current implementation, which I am not happy with, looks like this.
Register eventhandlers for user action, which lead to ajax requests.
For each request:
Determine which container is the target for the new content
Validate the ajax response
Pass the result to the appropiate rendering function if everything is as expected
Here is an example
function setGamedayScoringChangeHandlers() {
$("#community").delegate("div.community div.nav", "click", function() {
var orderId = $(this).html();
var communityId = $(this).closest('.communityView ').dashId();
requestGamedayScoringByOrderId(communityId, orderId);
});
}
function requestGamedayScoringByOrderId(communityId, orderId) {
var $targetContainer = $('#community-' + communityId + '-gameday');
$.ajax({
url: '?api=league&func=getGamedayScoringByCommunityIdAndOrderId',
data: {
communityId : communityId,
orderId : orderId
},
success: function(result) {
// custom indicator, that sth. didn't work as supposed
if (result.success === false) {
// a php error couldn't be handled as expected
if (result.error === 'phpRuntimeError') {
// ..
}
// ..
}
else {
renderGamedayScoring(result, $targetContainer);
}
}
});
}
Question
How can this and especially the redundant error checking be simplified? Could Reflection, in a sense of: "Is the response valid? And what does the error message say or data look like?" be a reasonable structure do deal with this? Additionally: Is the "coupling" of the actual ajax request and determing the $targetContainer a "normal" procedure?
Many thanks,
Robson
Yes I think register ajax handler trought one pipe is a good way, because it is more easy to control, you will have less redundant code and less boarding effects. If I look at your code comments it seems the response is not as you expect. I use to do like this for controling a group of ajax request talking with server script. I build one request object like :
// myscript.js
var rqPHP = {
url:'php/dispatcher.php', type:'POST', dataType:'json',
success:function(json, status, jXHR){
//console.log('rqPHP.succes : ', json);
if(!json) return console.warn('[rqPHP.success] json is null');
if(!json.cmd) return console.warn('[rqPHP.success] json.cmd is null');
if(!json.res) return console.warn('[rqPHP.success] json.res is null');
if(json.err && json.err.length){ console.warn('[rqPHP.success errors cmd:'+json.cmd+'] '+json.err);}
// so if no errors, dispatch actions based on original command asked
switch(json.cmd){
case 'loadfile' :
// do whatever with response
break;
case 'savefile' :
// do whatever with response
break;
}
},
error:function(jXHR, status, err){
console.warn('[rqPHP.error] ', status,',',err,',',jXHR.responseText);
}
};
then when use this object trought all my group of different actions and I precise wich action and arguments I pass. I use to ask for a json data so I am able to receive an easy parsing response, so I am able to return the original command asked, and some details on errors that may occured for example, and when I need to fire the request :
// myscript.js
rqPHP.data = {'cmd':'loadfile', 'filename':'file.dat', 'arg2':'other argument'};
$.ajax(rqPHP);
Then an example of one server script that will respond :
// dispatcher.php
$pv = $_POST;
$res = '';
$err = array();
// you check the command asked for :
switch(strtolower($pv['cmd'])){
case 'savefile' :
// do whatever
break;
case 'loadfile' :
// do whatever
if(any error){
$err[] = $loadError;// push error with whatever details you'll retrieve in javascript
}else{
$res = ',"res":"'.$dataLoaded.'"';// format json response so you'll check the var exist
}
break;
}
$jsonRes = '{"cmd":"'.$pv['cmd'].'"'.$res.',"err":"'.implode('|', $err).'"}';// json result
print $jsonRes;
They may be some errors, it is just for the principe, I hope that will help, just some last advices :
you should better use the requestObject.data to pass any arguments instead of setting the url like you did, this is much more easy because jQuery does the properly encoding work
you may use POST so the url stay clean, post vars are 'hidden'
in your case, because you may want to centralize server actions with ONE server script, you should use 'json' as dataType because it is much easier to retrieve details from the response, such errors. You have to distinct the ajax error that is trigger when the url doesn't exist, or access denied, well when the server replies it just can't respond to this request, and distinct the properly response of your server script, I mean the script responds well but it may occur an command error, for example for a 'loadfile' command, the argument fileUrl may be wrong or unreadable, so the action is done but the response will be not valid for you...
If you plan to fire many loads for differents parts (I mean you may don't wait response for an ajax before loading a new one), it should be better to set main success and errors functions for keeping centralization and then build one new request object each time you make a load
function rqSuccess(json, status, jXHR){
// put same checking code as before, then you can also retrieve some particular variables
// here, 'this' should correspond to the request object used for the $.ajax so :
console.log('myTarget is : ', this.myTarget, ' , myVariable is : ', this.myVariable);
}
function rqError(jXHR, status, err){
// put same checking code
}
// then each time you want make one or many independant calls, build a new request object
var myRq = {url:'dispatcher.php',type:'POST',dataType:'json',
success:rqSuccess,
error:rqError,
myTarget:$('#myblock'),// any variable you want to retrieve in response functions
myVariable:'Hello !',// after all it is an object, you can store anything you may need, just be carefull of reserved variables of the ajax object (see jQuery $.ajax doc)
// the data object is sanitized and sended to your server script, so put only variables it will need
data : {'cmd':'loadfile',...}
}
$.ajax(myRq);
// you may load an other independant one without waiting for the response of the first
var myRq2 = {...myTarget:$('#anotherblock'), data:{'cmd':'anotheraction'}...}
$.ajax(myRq2);
As a first step, you should change the error handling on the serverside to produce a non-OK/200 response for error cases, e.g. throw a 500. Then have that handled as an actual error on the clientside, along with other errors, instead of putting it through the success-callback.
That way you can use jQuery's abstractions for global error handling: http://api.jquery.com/ajaxError

Calling multiple views in CouchApp query

I need to search the CouchDB based on several criteria entered in a form. Name, an array of Tags and so on. I would then need various views to index on these fields. Ultimately, all the results will be collated in data.js and provided to mustache.html. Say there are 3 views - docsByName, docsByTags, docsById.
What I don't know is, how to query all these views in query.js. Can this be done and how ?
Or should the approach be of that to write one view that makes multiple emits for each search somehow ?
Thank you.
From what you say I assume you are using Evently, so I will quote from Evently primer:
The async function is the main star, which in this case makes an Ajax request (but it can do anything it wants). Another important thing to note is that the first argument to the async function is a callback which you use to tell Evently when you are done with your asynchronous action. [...] Whatever you pass to the callback function then becomes the first item passed to the data function.
In short: put your Ajax requests in async.js.
As a side note: Evently is only one of the possible choices to write a couchapp and it is not clear if it is maintained. However it works and it is easy to rearrange the code to not use it.
EDIT: here is a sample async function (cut&paste from an old program):
function(cb, e) {
var app = $$(this).app
;
app.db.openDoc('SOMEDOCID', {
error: function(code, error, reason) {
alert("Error("+code+" "+error+"): "+reason);
}
, success: function(doc) {
app.view('SOMEVIEWNAME', {
include_docs: true
, error: function(code, error, reason) {
alert("Error("+code+" "+error+"): "+reason);
}
, success: function(resp) {
resp.doc = doc;
cb(resp);
}
});
}
});
}

Resources