doesNotMatch query in Parse not working - parse-platform

I have two objects in Parse. The first one is notification where I save every challenge my user get. The second one is UserChallenge where I store every challenge a user completes. I tried to do a combined query where I only get results of notifications for challenges the user didn't complete and I get nothing in return. I checked my data and I should get two objects back.
Does anyone can tell what I did wrong in the query?
var Completed = Parse.Object.extend("Picok_User_Challenge");
var completedQuery = new Parse.Query(Completed);
completedQuery.equalTo("picok_user_id",currentUser);
var Challenges = Parse.Object.extend("Picok_Notifications");
var challengesQuery = new Parse.Query(Challenges);
challengesQuery.include("new_challenge_id");
challengesQuery.equalTo("type", "CHALLENGE");
challengesQuery.equalTo("who_recived", currentUser);
challengesQuery.doesNotMatchKeyInQuery("new_challenge_id","picok_challenge_id",
completedQuery);
challengesQuery.find({
success: function(results) {
console.log("createNotifiction success count: " + results.length);
response.success("YAY");
},
error: function(object, error)
{
console.log(error);
alert('Failed to get challenge not completed for: ' + request.params.user);
response.error('Failed to get user challenges to complete for: ' + request.params.user);`
}
});

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());
}

Possible Parse bug in matchesKeyInQuery

If a post in my Parse database is liked, I want to send a push to the author via cloud code.
To be able to send pushes to specific users, all installations store the objectId of the current user. To find the author of the liked post, I use the query
var userWhosePostWasLikedQuery = new Parse.Query(Parse.Installation);
userWhosePostWasLikedQuery.equalTo(kClassInstallationKeyCurrentUserId, userWhosePostWasLiked.id);
This works fine: A single push is sent to the author.
Now I want to send this push only if the author has such pushes enabled. Thus each user stores a push settings array with enable flags for different pushes.
I use now another query for all users who have such pushes enabled:
const User = Parse.Object.extend(kClassUser);
var pushEnabledUserQuery = new Parse.Query(User);
pushEnabledUserQuery.equalTo(kClassUserKeyPushSettings, kPushNotificationTypePostLiked);
This query correctly returns all users who have such pushes enabled.
Eventually, I want to constrain the query for installations with the author as current user, by this query for users who have pushes enabled. This is done in the following way:
var userWhosePostWasLikedQuery = new Parse.Query(Parse.Installation);
userWhosePostWasLikedQuery.equalTo(kClassInstallationKeyCurrentUserId, userWhosePostWasLiked.id);
userWhosePostWasLikedQuery.matchesKeyInQuery(kClassInstallationKeyCurrentUserId, kPFObjectId, pushEnabledUserQuery);
Since the old query without the 3rd line returns 1 user, the new query with the additional constraint (matchesKeyInQuery) should return the same user, since the author has pushes enabled.
But it returns 2 users, the author and another user who liked the post.
To my understanding, this looks like a Parse bug, since all constraints to a query are ANDed.
Any ideas, maybe for a workaround?
your var "kPFObjectId" should be change to "user".
the default parse Installation come with the pointer named "user" and not "kPFObjectId".
I can tell you that Im using the same method ("matchesKeyInQuery") and it is working well:
Parse.Cloud.define("sendPushForChat", function(request, response) {
var userId = request.params.userId;
var groupId = request.params.groupId;
var query = new Parse.Query('RecentActivity');
query.equalTo('groupId',groupId);
query.include('user');
query.notEqualTo('user', {__type: "Pointer", className: "_User", objectId: userId});
var queryInstallation = new Parse.Query(Parse.Installation);
queryInstallation.matchesKeyInQuery('user', 'user', query);
var message = request.params.messageContent;
Parse.Push.send({
where: queryInstallation,
data: {
alert: message,
badge: "Increment",
title: "מה נשמע?"
}
}, {
success: function() {
console.log("Push for chat was successful");
response.success('Push for chat was successful');
},
error: function(error) {
console.error(error);
response.error('error');
},
useMasterKey:true,
});
})

Parse: job status message must be a string

I have written a cloud code to change a Boolean value in table. The code is getting executed and the values are getting updated as well. But the issue is that I get the following error printed in my console. I am worried if this might cause a problem if the number of rows increase. Following is the error which is being printed on the console
I2015-09-15T06:15:48.317Z]v11: Ran job hello with:
Input: {}
Failed with: Error: Job status message must be a string
at updateJobMessageAndReturn (<anonymous>:1157:7)
at Object.success (<anonymous>:1211:9)
at e.obj.save.success (main.js:25:30)
at e.<anonymous> (Parse.js:12:27827)
at e.s (Parse.js:12:26759)
at e.n.value (Parse.js:12:26178)
at e.<anonymous> (Parse.js:12:26831)
at e.s (Parse.js:12:26759)
at e.n.value (Parse.js:12:26178)
at e.s (Parse.js:12:26887)
Following is the cloud code:
Parse.Cloud.job("hello", function(request, response) {
Parse.Cloud.useMasterKey();
var presentDate = new Date();
// presentDate.setDate(presentDate.getDate()-1);
presentDate.setHours(0,0,0,0);
var usersValid = new Parse.Query(Parse.User);
usersValid.equalTo("emailVerified", true);
//usersValid.greaterThan("updatedAt", presentDate);
var users = new Parse.Query("Properties");
users.matchesQuery("user",usersValid);
users.equalTo("verified", false);
users.limit(1000);
users.find({
success: function(results) {
console.log("Total new properties "+ results.length);
for (var i = 0; i < results.length; i++) {
var obj = results[i];
obj.set("verified", true);
obj.save(null,{
success: function (object) {
console.log("Success - "+i);
response.success(object);
},
error: function (object, error) {
console.log("Failed - "+i);
response.error(error);
}
});
}
},
error: function(error) {
console.log("failed");
}
});
When you call
response.success(object);
you're passing the full object that was just saved - but you shouldn't be. You can just call success with a simple status string, like 'OK', or with some element from the saved object, like its object id.
The more serious issue is that you're requesting 1000 items in the query and then updating and saving each individually - and in the save completion handler you're calling success or error. So, as soon as the first of those 1000 objects is saved you're telling the job it's complete and it can stop processing the rest.
You should change your job to use promises instead of old style callbacks and you should put all of the save promises into an array and wait for them to complete after your loop before you call success or error.

Using Parse's cloud code to automatically push an object from one user to another

I have a feature on my app where one user fills out a form and it saves it to parse. I want to have the object that is saved be sent to user b (there is a pointer to user b in the saved object). I have an afterSave function written for doing this, but am getting errors. Am still new to javascript, so I would greatly appreciate it if someone could help me out. Thanks in advance.
Parse.Cloud.define("sendDealToConfirm", function(request, response) {
var sender = request.user;
var recipientUserId = request.params.recipientId;
var task = request.params.task;
var price = request.params.price;
var address = request.params.address;
var time = request.params.time;
var taskP = request.params.taskP;
//send the push
var recipientUser = new Parse.User();
recipientUser.id = recipientUserId;
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo("user", recipientUser);
Parse.Push.send({
where: pushQuery,
data: {
alert: "You have a new deal to confirm!",
task: task,
poster: sender,
price: price,
address: address,
time: time,
taskP: taskP
}
}).then(function(){
response.success("Deal was sent successfully.")
}, function(error){
response.error("Deal failed to send:" + error.message);
});
});
Here is my iOS code
[PFCloud callFunctionInBackground:#"sendDealToConfirm"
withParameters: #{#"recipientId": self.doer, #"task": self.details[#"Task_Name"], #"price": self.dealPrice, #"address": self.dealAddress, #"time": self.dealTime, #"taskP": self.details[#"Task_Pointer"]}
block:^(NSString *success, NSError *error) {
if (!error){
NSLog(#"Push successful");
} else {
NSLog(#"Error in push %#", error);
}
}];
EDIT Here is the crash report
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'PFObjects are not allowed here.'
Your cloud code seems fine but is it possible that one of the objects of the following NSDictionary might be a PFObject?
#{#"recipientId": self.doer, #"task": self.details[#"Task_Name"], #"price": self.dealPrice, #"address": self.dealAddress, #"time": self.dealTime, #"taskP": self.details[#"Task_Pointer"]}
Because, afaik Parse do not allow PFObjects in Parse.Cloud.define
Try to pass the PFObjects id as NSString to the parameters and in the cloud code create an object with the id.

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