Parse - Get object from pointer on beforeSave? - parse-platform

I have an Offer object that I send to the server, when this offer is about to be created I need to send a push notification to the user. Offer has a pointer to User an the field is called "to".
How can I fetch an object from a pointer?
Parse.Cloud.beforeSave("Request", function(request, response) {
var userQuery = new Parse.Query("User")
userQuery.get(request.object.get("to").id, {
success: function (user) {
console.log("user: ", user);
var installationQuery = new Parse.Query("Installation");
installationQuery.equalTo("user", user);
Parse.Push.send({
where : installationQuery,
data : {
alert : "HEllo"
},
success : function() {
},
error : function() {
console.log("error finding installation: " + error);
}
});
},
error : function (error) {
console.log("ERRRRRRRRRR");
}
});
response.success();
});

To answer your question directly, you can use Parse.Query.get() or Parse.Object.fetch() to retrieve the object.
I'm assuming that the problem you see is that the object saves but the push notification isn't happening. The cause is that you're not waiting for the get() to complete before calling response.success() and returning.
Here's a couple ways to reconcile that:
Your existing code but with response.success() moved up:
Parse.Cloud.beforeSave("Request", function(request, response) {
var userQuery = new Parse.Query("User")
userQuery.get(request.object.get("to").id, {
success: function (user) {
console.log("user: ", user);
var installationQuery = new Parse.Query("Installation");
installationQuery.equalTo("user", user);
Parse.Push.send({
where : installationQuery,
data : {
alert : "HEllo"
},
success : function() {
response.success();
},
error : function() {
console.log("error finding installation: " + error);
}
});
},
error : function (error) {
console.log("ERRRRRRRRRR");
}
});
});
Simplified with Promises
Parse.Cloud.beforeSave("Request", function(request, response) {
request.object.get("to").fetch().then(function(user) {
var installationQuery = new Parse.Query("Installation");
installationQuery.equalTo("user", user);
return Parse.Push.send({
where : installationQuery,
data : {
alert : "HEllo"
}
});
}).then(function() {
response.success();
}, response.error);
});
Further simplified. If you're not using the data within user, you shouldn't need to fetch it just to pass a pointer to a query.
Parse.Cloud.beforeSave("Request", function(request, response) {
var installationQuery = new Parse.Query("Installation");
installationQuery.equalTo("user", request.object.get("to"));
return Parse.Push.send({
where : installationQuery,
data : {
alert : "HEllo"
}
}).then(function() {
response.success();
}, response.error);
});

Related

readTextAsync WinJS cannot work

I need to read content from file. I have global variable fileDate and I want to put content to this variable, but when I call load method, the variable is undefined.
var filename = "dataFile.txt";
var fileDate;
WinJS.UI.Pages.define("index.html", {
ready: function (element, options) {
loadDate();
console.log("main" + fileDate);
this.fillYearSelect();
},
function loadDate() {
return localFolder.getFileAsync(filename).then(function (file) {
return Windows.Storage.FileIO.readTextAsync(file).then(function (fileContent) {
fileDate = fileContent;
console.log("fileContent " + fileContent);
},
function (error) {
console.log("Błąd odczytu");
});
},
function (error) {
console.log("Nie znaleziono pliku");
});
}
Sorry for my English :)
Don't forget that javascript is asynchronous, when you call console.log("main" + fileDate), the method loadDate() is not finished, and that is why your fileDate is not defined (yet).
You could use promises to achieve this.
Here is an example based on your code :
var filename = "dataFile.txt";
var fileDate;
var applicationData = Windows.Storage.ApplicationData.current;
var localFolder = applicationData.localFolder;
function loadDate() {
return new Promise(function (onComplete, onError) {
localFolder.getFileAsync(filename).then(function (file) {
Windows.Storage.FileIO.readTextAsync(file).then(function (fileContent) {
fileDate = fileContent;
console.log("fileContent " + fileContent);
onComplete(fileDate);
},
function (error) {
console.log("Error on readTextAsync");
onError(error);
});
},
function (error) {
console.log("Error on getFileAsync");
onError(error);
});
});
}
Now loadDate()returns a promise, you can now use .then() method to do things when loadDate() is finished.
loadDate().then(function (fileDate) {
console.log("Content : " + fileDate);
},
function (error) {
console.log(error);
});

how to make two queries atomic in parse.com in beforeSave and afterSave triggers

I made two classes in parse User(by default) and UserData.
BeforeSave Trigger as follows:
Parse.Cloud.beforeSave(Parse.User, function(request, response) {
var userDataObject = new Parse.Object("UserData");
var fromUserPointer = {"__type":"Pointer","className":"_User","objectId":request.object.id};
return userDataObject.save({score: 0, ideasCount: 0, followersCount:0, return:0}).then(function (userData) {
var userDataPointer = {"__type":"Pointer","className":"UserData","objectId":userData.id};
request.object.set("userData", userDataPointer);
response.success();
}, function(error) {
response.error(error.message);
});
});
It saves user's UserData and takes its UserData pointer field and saves in UserData class.
Parse.Cloud.afterSave(Parse.User, function(request) {
Parse.Cloud.useMasterKey();
var userPointer = {"__type":"Pointer","className":"_User","objectId":request.object.id};
var userData = request.object.get("userData");
if (userData) {
var userDataPointer = {"__type":"Pointer","className":"UserData","objectId":userData.id};
var userDataQuery = new Parse.Query("UserData");
userData.set("user", userPointer);
return userData.save().then (function (userData) {
var activityObject = new Parse.Object("Activity");
return activityObject.save({fromUserData: userDataPointer, from:userPointer,
toUserData:userDataPointer, to:userPointer, type:"follow"});
}).then (function (success) {
}, function (error) {
console.error("Error in afterSave(user) : " + request.object.id + ":" + error.message);
});
}
});
The problem is that, before saving in the User class, it sometimes does not create UserData, which it should create. Hence these two triggers must run atomically, which they do not.

Parse Cloud job

I have a job in the parse cloud, inside the job I've a Parse.Cloud.run, when I run this function works fine and parse data base is update, but in the in the cloud job statuses appears failed. Here's my code:
Thanks in advance.
Parse.Cloud.job("updateTopsThreeJob", function(request, status) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query("_User");
query.descending("followersOfMe");
query.limit(3);
query.find({
success: function(results) {
var TestJS = Parse.Object.extend("testJS");
var test = new TestJS();
var listTops = [];
for (var i = 0; i < results.length; i++) {
var object = results[i].get("username");
listTops.push(object);
}
Parse.Cloud.run("updateTopsThree", {objects: listTops}, {
success: function(result) {
status.success("Migration completed successfully.");
response.success(result)
},
error: function(error) {
status.error("Uh oh, something went wrong.");
}
});
response.success(listTops);
},
error: function(error) {
response.error("failed");
}
});
});
Parse.Cloud.define("updateTopsThree", function(request, response) {
var tops = Parse.Object.extend("testJS");
var query = new Parse.Query(tops);
query.get(ObjIDs.topsThreeID(), {
success: function(topsThree) {
topsThree.set("topsThree", request.params.objects);
topsThree.save();
response.success(topsThree);
},
error: function(object, error) {
response.error(error);
}
});
});
The Parse Cloud Code runs much like any other javascript file. In order to declare another function to be called within the parse .js file, such as in this case, you do not need to define the function using Parse syntax. Define and call it just as you would a normal Javascript function.
Use this to call the function within your Parse.job:
updateTopsThree(topThreeObjects);
Define function:
function updateTopsThree(topObjects) {
var tops = Parse.Object.extend("testJS");
var query = new Parse.Query(tops);
query.get(ObjIDs.topsThreeID(), {
success: function(topsThree) {
topsThree.set("topsThree", topObjects);
topsThree.save();
response.success(topsThree);
},
error: function(object, error) {
response.error(error);
}
});
}
Thanks, but finally I´ve solved my problem as follows: I´ve created a cloud function like this:
Parse.Cloud.define("setLikesInDB", function(request, response) {
var query = new Parse.Query("testJS");
query.get(ObjIDs.topsLikesID(), {
success: function(topsThree) {
topsThree.set("topsLikes", "likes");
topsThree.save();
response.success(topsThree)
},
error: function(object, error) {
response.error(error);
}
});
});
And then into my Parse.Cloud.Job I´ve called a cloud function like this:
Parse.Cloud.run('setLikesInDB', {obj : listTops}, {
success: function(result) {
response.success(result);
},
error: function(error) {
response.error('some error')
}
});
This way works fine.
I hope this helps someone else.

Adding contraints to a column on Parse Data

I'm saving some objects into tables on my Parse Data. But I need to add a constraint or make sure that the data i'm trying to insert is unique. I'm using something like the following code. But i want to guarantee that the eventId (that I'm getting from facebook API) is unique in my tables, so i don't have any redundant information. What is the best way to make it work?
var Event = Parse.Object.extend("Event");
var event = new Event();
event.set("eventId", id);
event.set("eventName", name);
event.save(null, {
success: function(event) {
console.log('New object created with objectId: ' + event.eventId);
},
error: function(event, error) {
console.log('Failed to create new object, with error code: ' + error.message);
}
});
Update:
I'm calling it inside a httpRequest. The following is pretty much what I have and I cant figure out just how to call a beforeSave inside it.
Parse.Cloud.define("hello", function(request, response) {
var query = new Parse.Query("Location");
query.find({
success: function(results) {
console.log(results);
var totalResults = results.length;
var completedResults = 0;
var completion = function() {
response.success("Finished");
};
for (var i = 0; i < totalResults; ++i){
locationId = results[i].get("locationFbId");
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/'+locationId+'/events?access_token='+accessToken,
success: function(httpResponse) {
console.log(httpResponse.data);
console.log("dsa"+locationId);
for (var key in httpResponse.data) {
var obj = httpResponse.data[key];
for (var prop in obj) {
var eventObj = obj[prop];
if (typeof(eventObj) === 'object' && eventObj.hasOwnProperty("id")) {
var FbEvent = Parse.Object.extend("FbEvent");
var fbEvent = new FbEvent();
fbEvent.set("startDate",eventObj["start_time"]);
fbEvent.set("locationFbId", locationId);
fbEvent.set("fbEventId", eventObj["id"]);
fbEvent.set("fbEventName", eventObj["name"]);
Parse.Cloud.beforeSave("FbEvent", function(request, response) {
var query = new Parse.Query("FbEvent");
query.equalTo("fbEventId", request.params.fbEventId);
query.count({
success: function(number) {
if(number>0){
response.error("Event not unique");
} else {
response.success();
}
},
error: function(error) {
response.error(error);
}
});
});
}
}
}
completedResults++;
if (completedResults == totalResults) {
completion();
}
},
error:function(httpResponse){
completedResults++;
if (completedResults == totalResults)
response.error("Failed to login");
}
});
}
},
error: function() {
response.error("Failed on getting locationId");
}
});
});
So this is occurring in Cloud Code correct? (Im assuming since this is Javascript)
What you could do is create a function that occurs before each "Event" object is saved and run a query to make sure that the event is unique (query based off of "eventId" key, not objectId since the id comes from Facebook). If the event is unique, return response.success(), otherwise return response.error("Event not unique")
EX:
Parse.Cloud.beforeSave("Event", function(request, response) {
if(request.object.dirty("eventId")){
var query = var new Parse.Query("Event");
query.equalTo("eventId", request.object.eventId);
query.count({
success: function(number) {
if(number>0){
response.error("Event not unique");
} else {
response.success();
}
},
error: function(error) {
response.error(error);
}
});
} else {
response.success();
}
});
Parse.Cloud.define("hello", function(request, response) {
var query = new Parse.Query("Location");
query.find({
success: function(results) {
console.log(results);
var totalResults = results.length;
var completedResults = 0;
var completion = function() {
response.success("Finished");
};
for (var i = 0; i < totalResults; ++i){
locationId = results[i].get("locationFbId");
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/'+locationId+'/events?access_token='+accessToken,
success: function(httpResponse) {
console.log(httpResponse.data);
console.log("dsa"+locationId);
for (var key in httpResponse.data) {
var obj = httpResponse.data[key];
for (var prop in obj) {
var eventObj = obj[prop];
if (typeof(eventObj) === 'object' && eventObj.hasOwnProperty("id")) {
var FbEvent = Parse.Object.extend("FbEvent");
var fbEvent = new FbEvent();
fbEvent.set("startDate",eventObj["start_time"]);
fbEvent.set("locationFbId", locationId);
fbEvent.set("fbEventId", eventObj["id"]);
fbEvent.set("fbEventName", eventObj["name"]);
// Our beforeSave function is automatically called here when we save it (this will happen every time we save, so we could even upgrade our method as shown in its definition above)
fbEvent.save(null, {
success: function(event) {
console.log('New object created with objectId: ' + event.eventId);
},
error: function(event, error) {
console.log('Failed to create new object, with error code: ' + error.message);
}
});
}
}
}
completedResults++;
if (completedResults == totalResults) {
completion();
}
},
error:function(httpResponse){
completedResults++;
if (completedResults == totalResults)
response.error("Failed to login");
}
});
}
},
error: function() {
response.error("Failed on getting locationId");
}
});
});
This can also be accomplished before ever calling the save by querying and only saving if the query returns with a number == 0.
Summary: For those joining later, what we are doing here is checking to see if an object is unique (this time based on key eventId, but we could use any key) by overriding Parse's beforeSave function. This does mean that when we save our objects (for the first time) we need to be extra sure we have logic to handle the error that the object is not unique. Otherwise this could break the user experience (you should have error handling that doesn't break the user experience anyway though).

AJAX POST request never completes. Data posts to server

I am sending a post request via AJAX. The data successfully posts but the AJAX call never completes. Backbone on the front; Node on the back. I am including the save function from my backbone view and the express route.
save: function(event) {
event.preventDefault();
console.log( 'You signed up for ' + this.model.get('name'));
var name = this.model.get('name');
var courseDay = this.model.get('courseDay');
var time = this.model.get('time');
var location = this.model.get('location');
jQuery.post("/test/signups", {
"name" : name,
"courseDay" : courseDay,
"time" : time,
"location" : location,
}, function (data, textStatus, jqXHR) {
console.log("Post response:");
console.dir(data);
console.log(textStatus);
console.dir(jqXHR);
});
}
Route:
app.post('/test/signups', isLoggedIn, function (req, res){
User.findOne({'_id': req.user.id }, function(err, user) {
if (err)
return done(err);
if (user) {
user.signup.name = req.body.name;
user.signup.courseDay = req.body.courseDay;
user.signup.time = req.body.time;
user.signup.location = req.body.location;
user.signup.modified = req.body.modified;
user.update({$push: { "signup" :
{ name: user.signup.name,
courseDay: user.signup.courseDay,
time: user.signup.time,
location: user.signup.location,
modified: user.signup.modified
}
}},{safe:true, upsert:true},function(err){
if(err){
console.log(err);
} else {
console.log("Successfully added" + user.signup);
}
});
}
});
});
Your server side code needs to send a response. Try something like below. Note I try to cover all cases of an error, user not found, and user found.
app.post('/test/signups', isLoggedIn, function (req, res){
User.findOne({'_id': req.user.id }, function(err, user) {
if (err) {
return res.status(500).send(err);
}
if (user) {
user.signup.name = req.body.name;
user.signup.courseDay = req.body.courseDay;
user.signup.time = req.body.time;
user.signup.location = req.body.location;
user.signup.modified = req.body.modified;
user.update({$push: { "signup" :
{ name: user.signup.name,
courseDay: user.signup.courseDay,
time: user.signup.time,
location: user.signup.location,
modified: user.signup.modified
}
}},{safe:true, upsert:true},function(err){
if(err){
return res.status(500).send(err);
}
console.log("Successfully added" + user.signup);
res.send(user);
});
} else {
res.status(404).send();
}
});
});

Resources