Parse - Check for Update inside BeforeSave in Cloud Code - javascript

I want to check that I am not saving a duplicate entry for the attend status of an event - so on BeforeSave I am checking that the event rsvp has not already been entered - if it has, I want to know if it needs to be updated. If it does, I want to do an update instead of create a new RSVP entry.
This is my code - I can't seem to get it to work, even with the simplist update inside BeforeSave.
Parse.Cloud.beforeSave("Rsvps", function(request, response) {
var eventid = request.object.get("eventid");
var userid = request.object.get("userid");
var rsvp_status = request.object.get("rsvp_status");
var Rsvps = Parse.Object.extend("Rsvps");
var query = new Parse.Query(Rsvps);
query.equalTo("eventid", eventid);
query.equalTo("userid", userid);
query.first({
success: function(object) {
if (object) {
// response.error("An RSVP for this event already exists.");
request.object.id = object.id;
request.object.set('rsvp_status', "attending");
request.object.save();
} else {
response.success();
}
},
error: function(error) {
response.error("Error: " + error.code + " " + error.message);
}
});
});
I've tried so many variation of this without any joy - this my latest attempt.

#CityLogic you shouldn't have to call that second save in #ahoffer's example, because you are in the beforeSave trigger. Just set the resp_status and call response.success().

UPDATED. I added a check not to not update an existing object if the 'attending' value is correct. Give this a try. If there are any you cannot resolve, add the errors as a comment to this answer.
Parse.Cloud.beforeSave("Rsvps", function (request, response) {
var eventid = request.object.get("eventid");
var userid = request.object.get("userid");
var rsvp_status = request.object.get("rsvp_status");
//Do not re-declare the class
//var Rsvps = Parse.Object.extend("Rsvps");
var query = new Parse.Query("Rsvps");
//Check for existing RSVP
query.equalTo("eventid", eventid);
query.equalTo("userid", userid);
query.first().then(function (object) {
if (object && object.get('rsvp_status') != "attending") {
//RSVP exists and needs updating.
// Do not save the object attached to the request.
//Instead, update existing object.
object.set('rsvp_status', "attending");
object.save().then(function () {
response.error('Updated existing RSVP to "attending"');
},
function (error) {
response.error("Error: " + error.code + " " + error.message);
});
} else {
//Continuing and save the new RSVP object because it is not a duplicate.
response.success();
}
},
function (error) {
response.error("Error: " + error.code + " " + error.message);
});
});

Related

Retrieving values of objects in a parse database

So I'm trying to pull the name of the creator, just for testing purposes, from the session object. The creator object is a pointer but it keeps coming up as undefined however? Any clue why?
function joinLobby(){
var ses = Parse.Object.extend("Session");
var query = new Parse.Query(ses);
query.equalTo("Name", document.getElementById("lobby").value);
query.find({
success: function(results) {
console.log("Successfully retrieved " + results.length );
// Do something with the returned Parse.Object values
session = results[0];
addPlayer(session,player);
console.log("session joined: "+session.get("Name"));
console.log("The creator is: "+session.get("Creator").get("Name")); // coming up as undefined
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
}
This is because the query does not load the object pointed by the pointer. To do that you need to add this extra line and then run your query.
query.include("Creator");

Call update in Parse Cloud Code

I know there were similiar questions, but I see no solution in them.
I want to create new object if it doesn't exists in database, and update if one exists.
Here is my simple code :
Parse.Cloud.beforeSave("Tag", function(request, response) {
var query = new Parse.Query("Tag");
query.equalTo("name", request.object.get("name"));
query.first({
success: function(result) {
if (!result) {
response.success();
} else {
result.increment("popularityCount");
result.save();
}
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
});
As you see, I am calling it beforeSave. If query doesn't find anything, creates new entry. If query finds something, it should take this result, and popularityCount. But it doesn't. It works only if I call response.success() after that, but calling this function causes also in creating new entry.
It seems wrong to increment a counter on an object on every save. What if the object is modified for some other reason? If you really do want to increment a field on every save, there's no need for a query -- the object being saved is passed to the function. Moreover, a query will not work in the case where a new object is being saved.
How about instead, find or create the object as one operation, increment the counter when app logic calls for it
function findOrCreateTagNamed(name) {
var query = new Parse.Query(Tag);
query.equalTo("name", name);
return query.first().then(function(tag) {
// if not found, create one...
if (!tag) {
tag = new Tag();
tag.set("popularityCount", 0);
tag.set("name", name);
}
return (tag.isNew())? tag.save() : Parse.Promise.as(tag);
});
}
function incrementPopularityOfTagNamed(name) {
return findOrCreateTagNamed(name).then(function(tag) {
tag.increment("popularityCount");
return tag.save();
});
}
Now there's no need for beforeSave logic (which seems like the right thing to do, not a workaround).
Parse.Cloud.beforeSave("Tag", function(request, response) {
var tag = request.object;
tag.increment("popularityCount");
response.success();
});

Parse Javascript SDK Query for PFObject "User" returns nil

As the question title describes, I've created a custom PFObject class called "User". This class works as expected with the iOS SDK, but when I try and access this class from the Javascript SDK, the query returns null.
Here is the code I use to make the query:
function getUserWithID() {
Parse.initialize("...", "...");
var userID = "someid";
var User = Parse.Object.extend("User");
var query = new Parse.Query(User);
query.equalTo("userID", userID);
query.find({
success: function(results) {
alert("Successfully retrieved " + results.length + " users.");
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
}
Has anyone else run into this issue? Am I missing something or is there an issue with the SDK?
*This same snippet successfully retrieves objects of other classes.

Parse.com / Javascript - Save users objectid string as user pointer

How do I save a user pointer to an object when i have the object id of the user.
I am able to save the object to the class in Parse but the assignee is always 'Undefined' in Parse.
e.g. I have retrieved the user object and can get the username / object id etc through:
function getUserFromUsername(username) {
Parse.initialize("...", "...");
console.log('The username passed in is: ' + username);
var User = Parse.Object.extend("_User");
var query = new Parse.Query(User);
query.equalTo("username", username);
query.first({
success : function(result) {
// Do something with the returned Parse.Object values
var userPointer = new Parse.User();
userPointer = result;
console.log(userPointer.get('username')); // this returns the correct username
return userPointer;
},
error : function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
}
Which is called from my save task function below: (Note, I've logged all relevant fields and they return as expected.
function saveNewTask(clientName, taskTitle, taskDue, assigneeArray) {
Parse.initialize("...", "...");
var x;
for (x in assigneeArray) {
var Task = Parse.Object.extend("Tasks");
var task = new Task();
task.set("title", taskTitle);
task.set("date", taskDue);
var thisAssignee = GetUserFromUsername(assigneeArray[x]);
task.set('assignee', thisAssignee);
task.save(null, {
success : function(task) {
// Execute any logic that should take place after the object is saved.
console.log('New object created with objectId: ' + task.id);
},
error : function(gameScore, error) {
// Execute any logic that should take place if the save fails.
// error is a Parse.Error with an error code and message.
console.log('Failed to create new object, with error code: ' + error.message);
}
});
}
}
So you should save a pointer to the user to the task.
var Task = Parse.Object.extend("Tasks");
var task = new Task();
task.set("user", user);
task.set("title", "taskTitle");
task.set("date", taskDue);
task.save(null, {
success : function(task) {
// Execute any logic that should take place after the object is saved.
console.log('New object created with objectId: ' + task.id);
},
error : function(gameScore, error) {
// Execute any logic that should take place if the save fails.
// error is a Parse.Error with an error code and message.
console.log('Failed to create new object, with error code: ' + error.message);
}
});
By default, when fetching an object, related Parse.Objects are not fetched. These objects' values cannot be retrieved until they have been fetched like so:
var user = task.get("user");
user.fetch({
success: function(user) {
//fetch user is here
}
});
This is explained here: https://parse.com/docs/js_guide#objects-pointers
The problem with your script is when you are querying in Parse it is done asynchronously so you can't return the user immediately. Instead you need to return the promise and then handle it when you call getUserFromUsername:
function getUserFromUsername(username) {
var User = Parse.Object.extend("_User");
var query = new Parse.Query(User);
query.equalTo("username", username);
return query.first();
}
getUserFromUsername('testUsername').then(function(result) {
//use User here
}, function(error) {
alert("Error: " + error.code + " " + error.message);
});
Take a look at this document on promise chaining for more information about promises:

Generating and saving a list of ParseObjects within a Parse.Cloud.httpRequest in a cloud function

So, I'm defining a cloud function that's supposed to make a call to the foursquare api and generate a list of restaurants (each restaurant is a ParseObject) from the returned JSON. I successfully do this, but I run into problems when trying to save these objects to my database and send them back to my phone by calling response.success(). The large code block below saves the list to my database, but if I try
Parse.Object.saveAll(restaurants)
response.success(restaurants)
I end the function before all of the restaurants are saved. I tried using this line instead
Parse.Object.saveAll(restaurants).then(response.success(restaurants))
, but only half of the restaurants get saved before I get the error "Failed with: Uncaught Tried to save an object with a pointer to a new, unsaved object." I also get this error if I call response.success(restaurants) without attempting to save the list. I read that this is a bug in parse preventing someone from printing or passing unsaved ParseObjects. Any ideas? I also tried using .then on the http request, but I get the same issues or a new error: "com.parse.ParseException: i/o failure: java.net.SocketTimeoutException: Read timed out. "
Parse.Cloud.define("callFourSquare", function(request, response) {
//The Parse GeoPoint with current location for search
var geo = request.params.location;
var geoJson = geo.toJSON();
var url = "https://api.foursquare.com/v2/venues/explore?ll=" + geoJson.latitude + ","
+ geoJson.longitude + "&section=food&sortByDistance=1&limit=50&venuePhotos=1&categoryId=4d4b7105d754a06374d81259&client_id= C043AJBWKIPBAXOHLPA0T40SG5L0GGMQRWQCCIKTRRVLFPTH"
+ "&client_secret=Y1GZZRHXEW1I3SQL3LTHQFNIZRDCTRG12FVIQI5QGUX0VIZP&v=20140715";
console.log(url);
//Call to FourSquare api, which returns list of restaurants and their details
Parse.Cloud.httpRequest({
method: "GET",
url: url,
success: function (httpResponse) {
var restaurants = [];
var json = httpResponse.data;
var venues = json.response.groups[0].items;
console.log(venues.length)
for(i = 0; i < venues.length; i++) {
venue = venues[i].venue;
var RestaurantObject = Parse.Object.extend("Restaurant");
var rest = new RestaurantObject();
try {
rest.set("geoLocation",
new Parse.GeoPoint({latitude: venue.location.lat,
longitude: venue.location.lng}));
} catch(err) {}
try {
rest.set("address", venue.location.address + " " + venue.location.formattedAddress[1]);
} catch(err) {}
try {
rest.set("phoneNumber", venue.contact.formattedPhone);
} catch(err) {}
try {
rest.set("website", venue.url);
} catch(err) {}
rest.set("name", venue.name);
rest.set("lowerName", venue.name.toLowerCase());
try {
rest.set("priceLevel", venue.price.tier);
} catch(err) {}
try {
rest.set("rating", venue.rating/2);
} catch(err) {}
try {
rest.set("storeId", venue.id);
} catch(err) {}
try {
rest.set("icon", venue.photos.groups[0].items[0].prefix + "original"
+ venue.photos.groups[0].items[0].suffix)
} catch(err) {}
restaurants.push(rest);
}
Parse.Object.saveAll(restaurants);
},
error: function (httpResponse) {
response.error("Request failed with response code:" + httpResponse.status + " Message: "
+ httpResponse.text);
}
});
});
I believe your issue is that you aren't returning the Promise from Parse.Object.saveAll(restaurants) when your httpRequest() is complete. Try returning that saveAll() promise and see if it completes.

Categories