Using a query count inside an afterSave trigger (Parse.com cloud code) - parse-platform

I have a small afterSave trigger in my parse cloud code. The trigger just re-counts items that are flagged as deleted=false.
When I update my object, the count goes just fine, except when I update the deleted flag. It seems like the count is considering objects BEFORE the save event, which is not what I would expect from an "afterSave" trigger.
On the other hand, by using a "find" instead of a "count" on the very same query, I will always get the right number of objects. Of course the "find" way will go just when the query stays below 1000 objects.
Is there something wrong in my code? Is it the expected behavior? Is it a bug? Any alternative way to count objects the right way?
Thank you so much for your attention
Parse.Cloud.afterSave("BranchLike", function(request) {
console.log("Managing branchLike after save...");
Parse.Cloud.useMasterKey();
var branch = request.object.get("branch");
var branchLikeClass = Parse.Object.extend("BranchLike");
var type = request.object.get("type");
var branchLikeQuery = new Parse.Query(branchLikeClass);
branchLikeQuery.equalTo("branch",branch);
branchLikeQuery.equalTo("deleted",false);
branchLikeQuery.equalTo("type",type);
branchLikeQuery.count({
success: function(count) {
console.log("count = "+count); //works fine except on "delete" flag updates
/* ... */
},
error: function(error) {
/* ... */
}
});
branchLikeQuery.find({
success: function(branchLikes) {
console.log("ALTERNATIVE COUNT = "+branchLikes.length); //works fine when having less than 1000 objects
},
error: function(error) {
/* ... */
}
});
});

Related

How to update an User with useMasterKey in Parse

Issue Description
I'm trying to update an User when another user click on my Xamarin button.
Then, I used Cloud Code to perform this but it doesnt work
My Code
Here is my complete JS code :
Parse.Cloud.beforeSave("Archive", function(request, response) {
Parse.serverURL = 'https://pg-app-0brffxkawi8lqvf2eyc2isqrs66zsu.scalabl.cloud/1/';
var status = request.object.get("status");
if (status == "validated") {
var event = request.object.get("event");
event.fetch({
success: function(myEvent) {
var coinsEvent = myEvent.get("coins");
var user = request.object.get("user");
user.fetch({
success: function(myUser, coinsEvent, user) {
var email = myUser.get("email");
var coinsUser = myUser.get("coins");
myUser.set("coins", coinsUser + coinsEvent);
return myUser.save(null, {useMasterKey:true});
}
});
}
});
}
response.success();
});
I think myUser.save(null, {useMasterKey:true}); should work
I actually have that error :
Dec 24, 2017, 12:27 GMT+1 - ERRORError generating response for [PUT] /1/classes/_User/1GPcqmn6Hd
"Cannot modify user 1GPcqmn6Hd."
{
"coins": 250
}
Environment Setup
Server
parse-server version : v2.3.3
Server: Sashido
Your success branch never calls response.success() which is a problem... though maybe not THE problem.
You are also doing 2 fetches inside a 'beforeSave' function which is not recommended. 'BeforeSave' must happen very quickly and fetches take time. I would consider thinking through other options.
If you really need to do it this way, consider doing a Parse.Query("event") with an include("user") and trigger the query with query.first({useMasterKey:true}).
Are you sure coinsEvent is what you think it is? Fetch only returns the object fetched... not sure that you can curry in other parameters. I would change your final success routine to (double checking that coinsEvent is valid):
success: function(myUser) {
var coinsUser = myUser.get("coins");
myUser.set("coins", coinsUser + coinsEvent);
return myUser.save(null, {useMasterKey:true}).then(_ => response.success());
}

Does Parse limits saveall batches to 20 items automatically?

I'm still learning how to use Parse and I'm working with migrating a subset of a database with 49 items. I read that Parse saveAll should be able to handle batches of 70-100 with no issues but when ever I run the code below, Parse always only saves 20 items.
I run a query to draw out all items with .each(), then I create new parse Objects and insert them into an array.
Once the each() finishes, the array contains all 49 elements but when saveAll runs, only 20 items are saved.
I read thru promises but I'm not certain how they'll work with saveAll, additionally, most people here don't seem to be having any issues with saveAll.
I've tested the code below as a background and cloud function.
Parse.Cloud.job("testEach2", function(request, response) {
var eachQuery = new Parse.Query("test_csv");
var Item = Parse.Object.extend("Item");
var toSave = [];
eachQuery.each(
function(result) {
var item = new Item();
item.set("name",result.get("v_products_name_1"))
console.log(item.name)
toSave.push(item)
}, {success: function(result) {
response.success();
console.log(toSave.length);
Parse.Object.saveAll(toSave).then(function(results){
console.log("Objects were saved!");
response.success("Awesome");
},function(error){
console.log(error);
response.error(error);
});
}, error: function() {} });
});
You should call response.success(); only after Parse.Object.saveAll() is finished. Remove the first response.success(); from your success callback.

PARSE check original object on BeforeSave

I need to check the original object on before save to see what value has changed. currently i have this:
Parse.Cloud.beforeSave("Stats", function(request, response) {
if (!request.object.isNew()){
var query = new Parse.Query("Stats");
query.get(request.object.id, {
success: function(oldObject) {
alert('OLD:' + oldObject.get("Score") + "new:" + request.object.get("Score"));
/*Do My Stuff Here*/
response.success();
},
error: function(oldObject, error) {
response.error(error.message);
}
});
}else{
response.success();
}
});
The problem is that oldObject is equal to request.object.
Also the alert result is this: OLD:10 new:10, but the real old score was 5. Also according to the before save input log the original is really 5.
Any ideia what i am doing wrong?
Edit:
Here is the before save log.
before_save triggered for Stats as master:
Input: {"original":{"achievements":[],"Score":"100"updatedAt":"2015-11-02T10:09:24.170Z"},"update":{"Score":"110"}}
Result: Update changed to {"Score":"110"}
Edit2:
Is there any way to get the dirty value?
console.log("dirty: "+ request.object.dirty("score"));
I2015-11-03T14:23:12.198Z]dirty: true
The official way to know if a field was modified is to call dirty().
My guess is that querying for that particular object somehow updates all "instances" of that object in the current scope, and that's way dirty() works only if called before the query.
An option to get both the old and the new value is to mantain it in a separate field. For example, from your client you could call (pseudocoding, but you get the point):
// OldScore here is 0
statObject.put("Score") = 100;
statObject.saveInBackground();
Then in Cloud Code:
Parse.Cloud.beforeSave("Stats", function(request, response) {
var stat = request.object;
if (!stat.isNew()){
if (stat.dirty("Score")) {
var newValue = stat.get("Score") // 100
var oldValue = stat.get("OldScore") // 0
// Do other stuff here
stat.put("OldScore", newValue);
response.success();
} else {
response.success();
}
} else {
response.success();
}
});
However the issue you are describing is somewhat strange. Maybe you could try with the fetch() command; it should return the old value. However it will invalidate every other dirty field.

Parse, JS Updates in Real Time

I have the following code, where I have a myBool (a boolean) in my Data Browser initially set to false,
however sometime while I'm still viewing my page I have code set to turn it to true.
How can I make a real time update that will automatically hide my #div when myBool turns to true?
var myBool = currentUser.get("myBool");
if(myBool) {
$('#div').hide();
}
I did some research and found that the Parse.Cloud.afterSave() function may be useful, but I don't see how it will update the content automatically?
Hope I've been clear!
Thanks.
Edit:
Possibly something like this in my main.js?
Parse.Cloud.afterSave("setBool", function() {
var query = new Parse.Query(Parse.Installation);
query.equalTo('myBool', true);
Parse.Push.send({
where: query,
}, {
success: function() {
$('#div').hide();
},
error: function(error) {
$('#div').show();
}
});
});
Your problem with your afterSave function is that your calling it for a function rather than a class.
AfterSave is called after an object from a certain class is saved. If your bool
Parse.Cloud.afterSave(Parse.Installation, function(request) {
// Send push here, use request to target correct user
});
Additionally your push listener should be the one modifying the divs, not the CloudCode.

Update or insert new parse object using cloud code

As many who came before me, I'm trying to run a bit of cloud code that will check for uniqueness and then insert or update the object as necessary.
The code correctly determines whether or not there is an existing object in the db with the same device token as the request.object
However, the existing object will not update it's countdownValue to 200.
I have tried adding and omitting the object.save() function
I have tried adding, omitting, and exchanging the response.error and response.success functions
The preexisting object remains untouched in all cases.
I have tried Updating existing Parse object in Cloud Code and many others.
Any help or thoughts would be greatly appreciated.
var Countdown = Parse.Object.extend("Countdown");
Parse.Cloud.beforeSave("Countdown", function(request, response) {
if (!request.object.get("devicetoken")) {
response.error('A Countdown must have a devicetoken.');
} else {
var query = new Parse.Query(Countdown);
query.equalTo("devicetoken", request.object.get("devicetoken"));
query.first({
success: function(object) {
if (object) {
object.set("countdownValue", "200");
object.save();
response.error("Failing on purpose");
}
else
{
response.success();
}
},
error: function(error) {
response.error("Could not validate uniqueness for this Countdown object.");
}
});
}
});

Resources