Parse Cloud Code retrieving a user with objectId - parse-platform

I am trying to get the user object from objectId. I know the objectId is valid. But I can get this simple query to work. What is wrong with it? user is still undefined after the query.
var getUserObject = function(userId){
Parse.Cloud.useMasterKey();
var user;
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("objectId", userId);
userQuery.first({
success: function(userRetrieved){
console.log('UserRetrieved is :' + userRetrieved.get("firstName"));
user = userRetrieved;
}
});
console.log('\nUser is: '+ user+'\n');
return user;
};

Quick cloud code example using promises. I've got some documentation in there I hope you can follow. If you need more help let me know.
Parse.Cloud.define("getUserId", function(request, response)
{
//Example where an objectId is passed to a cloud function.
var id = request.params.objectId;
//When getUser(id) is called a promise is returned. Notice the .then this means that once the promise is fulfilled it will continue. See getUser() function below.
getUser(id).then
(
//When the promise is fulfilled function(user) fires, and now we have our USER!
function(user)
{
response.success(user);
}
,
function(error)
{
response.error(error);
}
);
});
function getUser(userId)
{
Parse.Cloud.useMasterKey();
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("objectId", userId);
//Here you aren't directly returning a user, but you are returning a function that will sometime in the future return a user. This is considered a promise.
return userQuery.first
({
success: function(userRetrieved)
{
//When the success method fires and you return userRetrieved you fulfill the above promise, and the userRetrieved continues up the chain.
return userRetrieved;
},
error: function(error)
{
return error;
}
});
};

The problem with this is that Parse queries are asynchronous. That means that it will return user (null) before the query has time to execute. Whatever you want to do with the user needs to be put inside of the success. Hopefully my explanation helps you understand why it's undefined.
Look into Promises. It's a nicer way of calling something after you get the result from the first query.

Related

Session token empty for parse cloud code user query

I have written the following query to query a user with a given email and once found, return the session key.
Upon executing it returns an empty response.
I double checked that the user session entry actually exists and is linked to the user I am querying.
var query = new Parse.Query(Parse.User);
var email = request.params.email;
query.equalTo("email",email);
query.first({
success: function(user) {
Parse.Cloud.useMasterKey();
response.success(user.getSessionToken());
},
error: function(user, error) {
response.error(error);
},
useMasterKey: true
});
Ok, since you are using parse.com and not parse-server you need to write
the following line of code:
Parse.Cloud.useMasterKey();
in the first line because you tell cloud code that you want to use master key before you are executing any request to the server. Also it's better to use Promises (according to the best practices)
so at the end your code should look like this:
For running on parse.com
// in parse.com - it's the first thing that you do
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
var email = request.params.email;
query.equalTo("email", email);
query.first().then(function(user) {
response.success(user.getSessionToken());
}, function(error) {
response.error(error);
});
For parse-server
in parse-server you use useMasterKey and send it to the function.
Parse.Cloud.useMasterKey(); will not work here.
// in parse-server - you send useMasterKey to the function
var query = new Parse.Query(Parse.User);
var email = request.params.email;
query.equalTo("email", email);
query.first({
useMasterKey: true
}).then(function(user) {
response.success(user.getSessionToken());
}, function(error) {
response.error(error);
});

Parse.com background job fail the service is currently unavailable

I am using Cloud Code to update all users, everyday. It used to work, but now getting error after 5 minute processing. "the service is currently unavailable" without any reason. I have checked status.parse.com and there is no relevant down. I have 10 000 users.
Parse.Cloud.job("makeUsersPassiveAndSendPushes", function(request, status) {
Parse.Cloud.useMasterKey();
var activeUsers = [];
var limitDoneUsers = [];
var nowDate=new Date();
var updatedUsers = [];
var query = new Parse.Query(Parse.User);
query.equalTo("passive",false);
query.each(function(user) {
if(user.get("passive") === false){
activeUsers.push(user);
user.set("passive", true);
user.set("passiveDate",nowDate);
}
if(user.get("isLimitDone")){
limitDoneUsers.push(user);
}
user.set("isLimitDone",false);
user.set("activeMatch",null);
user.set("canGetMatch",true);
user.set("dailyMatchEndCount",0);
//user.set("lastMatchLimit",false);
user.set("todaysMatches",[]);
updatedUsers.push(user);
return user.save();
})
Could you help me? Thanks.
You may want to try modifying the last line from:
return user.save();
to use callbacks for the save function, to ensure they are firing in sequence:
return user.save(null, {
success: function (user) {
return user;
},
error: function (error) {
return Parse.Promise.error(new Error("error"));
}
});
Another alternative would be to use the saveAll function like this:
return Parse.Object.saveAll(updatedUsers).then(function() {
//code that fires after all objects are saved
});
Also, are you using the hosted Parse.com environment or have you transitioned to another provider like Heroku & mLab?
As a fellow Parse user with this same issue (background job failing with this error when performing many inserts), I look forward to any comments you may have.

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.

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.");
}
});
}
});

Parse - afterSave and accessing request object?

I send a request to parse that includes a Comment object that has a pointer to a User named "from".
In afterSave I need to read this and I'm having all kinds of problems. beforeSave works just fine, but I want to execute this code in afterSave;
Parse.Cloud.afterSave("Comment", function(request) {
var userQuery = new Parse.Query("User");
userQuery.get(request.object.get("from").id, {
success: function(user) {
},
error : function(error) {
console.error("errrrrrrrr" + error);
}
});
});
Here is the log I'm seeing on parse
errrrrrrrrr [object Object]
EDIT:
I also tried
var userQuery = new Parse.Query("_User");
Seems like I had to call useMasterKey, since I was fetching a user data.
I'm not entirely sure about this though so I'll keep this question open.
Parse.Cloud.useMasterKey();
Have you tried this?
var userQuery = new Parse.Query(Parse.User);
Try to fetch the pointer directly:
var fromUserPointer = request.object.get("from");
fromUserPointer.fetch().then(function(fetchedFromUser){
},function(error){
});
Slightly different approach.
This assumes that you have the comment object available right there, or at least its id.
Instead of querying the User collection, how about this:
var commentQuery = new Parse.Query("Comment");
commentQuery.include("from");
commentQuery.get(<commentId>, {
success: function (comment)
{
var user = comment.get("from"); // Here you have the user object linked to the comment :)
},
error: function (error)
{
console.log("ERROR: ");
console.log(error);
}
});

Resources