Parse Server Cloud Code Save Object - javascript

I am attempting to query an object add 1 to the returned integer and then save this object back to my mLabs database using parse server cloud code.
I can successfully query and add 1 to the object that I would like, however I cannot figure out how to successfully save this back to the database. I have tried many solutions all leading to a Parse Server "request timeout"
Parse.Cloud.define("addRating", function(request, response) {
var currentRatingQuery = new Parse.Query("StudentNotes");
currentRatingQuery.equalTo("objectId", "Y4bBzvsHb1");
currentRatingQuery.select("noteRating");
currentRatingQuery.find({
useMasterKey: true,
success: function(results) {
//var noteRating = results.get("noteRating");
//noteRating += 1;
results = Number(results);
results += 1;
console.log("NOTE RATINGGGGG: " + results);
console.log("TYPE OFFFFFFF: " + typeof results);
results.set('institution', "TEST INSTITUTION");
results.save(null, {
useMasterKey: true
});
console.log("SAVE SUCCESS", results);
response.success("rating updated successfully.", results);
},
error: function(error) {
response.error("failed to add 1 to parse cloud code rating. Error: " + error); //THIS GETS CALLED
}
});
});
The code above successfully queries the database, but does not save the value back. It results in a Parse Server "request timeout".

My problem was syntax related there is a severe lack of syntax for parse server cloud code due to it being so similar to parse.com cloud code. The following is the working code to retrieve an object and save the object back.
Parse.Cloud.define('addNoteRating', function(request, response) {
var SaveObject = Parse.Object.extend("StudentNotes");
var saveObject = new Parse.Query(SaveObject);
saveObject.equalTo("objectId", request.params.objectId);
saveObject.first({
useMasterKey: true,
success: function(Objects) {
Objects.save(null, {
useMasterKey: true,
success: function(object) {
object.increment("noteRating");
object.save();
console.log("Cloud Code: User note rating has increased by 1.", object);
response.success('Cloud Code: User note rating has increased by 1.');
}
});
}
});
});

Timeout may cause by no response.
Try to add response when api failed, and see what is happened.
BTW, If you what response when increment success, response when save complete.
Parse.Cloud.define('addNoteRating', function(request, response) {
var SaveObject = Parse.Object.extend("StudentNotes");
var saveObject = new Parse.Query(SaveObject);
saveObject.equalTo("objectId", request.params.objectId);
saveObject.first({
useMasterKey: true,
//this function will get at most one object
success: function(object) {
if(object){
object.increment("noteRating");
object.save(null,{
//do not use master key?
success: function(note){
//u should wait the non-blocking call success and finish
console.log("Cloud Code: User note rating has increased by 1.", object);
response.success('Cloud Code: User note rating has increased by 1.');
}, error: response.error
});
}else{
response.error('this student note is not exist');
}
}, error: response.error
});
});
If this object is existed, you can just rewrite your code as below
Parse.Cloud.define('addNoteRating', function(request, response) {
var SaveObject = Parse.Object.extend("StudentNotes");
var studentNote = new SaveObject();
studentNote.id = request.params.objectId;
studentNote.increment("noteRating");
//student.save(null,{useMasterKey:true}).then(
studentNote.save().then(
function(note){
console.log("Cloud Code: User note rating has increased by 1.", object);
response.success('Cloud Code: User note rating has increased by 1.');
}, response.error
)
});

Related

Trying to make an AJAX call asynchronous in Javascript

I am trying to retrieve some data from neo4j for my web app. I have my code structured in the following manner:
When I click the button to retrieve the data, call
var childNodes = getAllChildNodes(uuid, ""); //uuid: node specific id in neo4j, second param not important
//do something with childNodes
....
In getAllChildNodes(),
function getAllChildNodes(uuid, filter) {
/*
prepare json data to send
*/
var resultNodes = {}
var successFunction = function(data) {
//store data in resultNodes ...
//do something with the data ...
}
var failFunction = function(xhr, status, error) {
//if query fails
};
//call to API function
try {
getChildrenAPI(jsonData, successFunction, failFunction)
} catch (err) { console.log(err) }
return resultNodes
}
In getChildrenAPI
function getChildrenAPI(jsonData, doneFunction, failFunction) {
var request = $.ajax({
method : 'POST',
url: myurl,
data : JSON.stringify(jsonData),
dataType : 'json',
contentType : 'application/json',
cache : false,
async : true,
});
request.done(function (data) {
doneFunction(data)
})
request.fail(function (xhr, status, error) {
failFunction( xhr, status, error );
});
}
The problem is that my childNodes var does not get populated. When I inspected further, in my getAllChildNodes() function, resultNodes is returned before the query data is stored in successFunction(). I thought this would be an async issue, so I made sure to check that the AJAX call had its async property set to true, but that didn't solve it. So I tried using async await on my getAllChildNodes(), but that didn't work either. So my question is, what am I doing wrong here? I'm still new to the idea of async so this was the best I can do. If someone can please help me with this I would really appreciate it.
It seems that you misunderstood the problem. AJAX requests are asynchronous by default. What you want, as far as I can tell by seeing your code is to be able to use the result of the request after the request in the code. For that you need to make it synchronous. You can specify async to be true, you can await and so on. However, it's a terrible idea in most cases to make your requests asynchronous. If you synchronize your request, then nothing else will run and your page will hang while you await.
What if a request lasts for 10 seconds? In that case your page is unresponsive for ten seconds if you synchronize the request.
What if you send 100 requests and on average they take 1 second? Then your page hangs for 100 seconds.
The best practice is to avoid syncrhonising your requests whenever possible and only do so when absolutely necessary. Instead, you will need to get used to callbacks, that is, functions defined to be executed once the request is completed and define the post-request behavior in them. You could also use promises or web workers, depending on your exact situation.
async function getAllChildNodes(uuid, filter) {
/*
prepare json data to send
*/
var resultNodes = {}
var successFunction = function(data) {
//store data in resultNodes ...
//do something with the data ...
}
var failFunction = function(error) {
//if query fails
};
//call to API function
try {
var data = await $.ajax({
method : 'POST',
url: myurl,
data : JSON.stringify(jsonData),
dataType : 'json',
contentType : 'application/json',
cache : false,
async : true,
});
successFunction(data);
} catch (err) {
console.log(err);
failFunction(err);
}
return resultNodes
}
var childNodes = getAllChildNodes(uuid, "");
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js" integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI=" crossorigin="anonymous"></script>
Javascript is single-threaded & non-blocking language so it will not execute code asynchronously.
To make your code sync, you have to create an async function that manage the async code (ajax, timeout, read a file, ...)
I think you're looking for something like the following:
getAllChildNodes(uuid, "", function done(results) {
// Results populated by the done callback.
console.log(results);
});
The trick here is that you need to be keeping track of how many requests were kicked off and when they finished.
So we can then change the definition of getAllChildNodes to call our doneCallback once all requests have been "processed".
function getAllChildNodes(uuid, filter, doneCallback) {
// How many calls do we need to make.
const callsToMake = [1,2,3];
// Track when all calls were made by the results.
const results = [];
const ajaxDoneCallbackCheck = function () {
if (results.length === items.length) {
doneCallback(results);
}
};
const ajaxSuccessCallback = function (data) {
results.push(data);
ajaxDoneCallbackCheck();
};
const ajaxFailCallback = function (error) {
results.push(error);
ajaxDoneCallbackCheck();
}
// Iterate through ajax calls to make.
for (const callToMake of callsToMake) {
// Do ajax stuff.
console.log('Request data');
getChildrenAPI(ajaxSuccessCallback, ajaxFailCallback);
}
}
Now results needs to be processed in our original done callback like so:
getAllChildNodes(uuid, "", function done(results) {
// Results populated by the done callback.
console.log(results);
// Iterate results.
for (const result of results) {
if (result instanceof Error) {
console.error(result);
} else {
// Process or track result!
console.log(result);
}
}
});

Update a p element from a nodejs function

I need to send a value from a input form to a nodejs server, which triggers a calculation with this value and needs to update an p element with the result of the calculation on the client side.
How can this be done?
This is what i have:
//Server side:
app.post('/calculate/:id', function(req, res){
var title = 'Tax Calculation';
var tax= taxcalculation(req.params.id);
res.render('index', {
title: title,
tax: tax,
});
});
//Client side:
var income= document.getElementById("income");
var tax = document.getElementById("tax")
$(income).on('change', function() {
console.log("changed");
$.ajax({
type: 'POST',
url: '/calculate/'+income.value,
success: function() {
$('#tax').html('<%= tax %>');
},
error: function() { // if error occured
alert("Error occured, please try again");
},
});
});
Okay, so you don't give a lot of data, but this sounds as simple as sending a response with the results to the client side in your Node web service that does the calculations and append the result to the P element
Your server code to handle the ajax call should output a json response which will contain the content for the <p>. It should not re-render the whole index page. I don't do a lot of node.js so I'll leave that for you to figure out.
The ajax success function should accept a response as a parameter, and then operate on that response.
Assuming the server response to this ajax request is of the format {"tax": 15.99}:
$.ajax({
type: 'POST',
url: '/calculate/'+income.value,
success: function(response) {
if (response.tax || response.tax === 0) {
$('#tax').html(response.tax);
}
},
error: function() { // if error occured
alert("Error occured, please try again");
},
});

Parse server query each with useMasterKey parameter

I'm migrating from Parse to Parse server. Most of my code is made without promises.
For this to work, I have to send the parameter: useMasterKey: true (where necessary) for each query / save.
For find and get queries or fetch objects, I have no problems, example:
Parse.com (find)
query.find({
success: function(results) {
//...
Parse Server (find)
query.find({useMasterKey: true
}).then(function(results) {
//....
Parse.com (fetch)
user.fetch({
success: function(user) {
//...
Parse Server (fetch)
user.fetch({useMasterKey: true,
success: function(user) {
//....
The problem is with each functions:
Parse.com (each)
query.each(function(comment) {
//...
Parse Server (each)
query.each({useMasterKey: true
}).then(function(comment) {
//....
It does not work.
Thanks
Although the docs don't suggest that the useMasterKey option is supported for an each query, having tested and verified myself it is in fact possible. Syntax as follows:
query.each(callback, {useMasterKey: true})
Where callback is a function that is called for each result of the query.
The each method of a query support useMasterKey, it's passed as an argument after the callback function, that will be executed for each result of the query.
The syntax is:
query.each(function (object, error) {
// Your function code
}, {
useMasterkey: true
})
Where object is a result for the query and error is a possible error that happened.
But, as shown here, it's better to just use useMasterKey for when you're actually changing something in the database:
query.each(function (object, error) {
object.destroy({
success: function (object) {
console.log("Successfully destroyed object.")
},
error: function (error) {
console.log("Error: " + error.code + " - " + error.message)
},
useMasterKey: true
})
})

How to make multiple HttpRequests with pagination cursors in Parse Cloud

I want to make a HTTP GET request from a url and it will contain the url of next webpage. I have to continue this process till I get an empty "next" url.
My code is as follows:
Parse.Cloud.define("myFunc", fucntion (request, response){
Parse.Cloud.httpRequest({
url: fb_url
}).then(function(httpResponse) {
next_url = httpResponse.data.next_url;
/******************/
// code to make another HttpRequest with next_url and iteratively
// doing it till next_url is null
response.success(httpResponse.text);
}, function(httpResponse) {
response.error("error " + httpResponse);
}
});
I tried a lot of different ways, but all in vain. Can anyone tell me how can I make another HttpRequest with the next_url and keep doing it until next_url is null.
Wrap the http invocation in a function that can be called recursively. This will return a chain of promises that make the requests until null is returned.
function keepGetting(url) {
return Parse.Cloud.httpRequest({ url:url }).then(function(httpResponse) {
nextUrl = httpResponse.data.nextUrl;
return (nextUrl === null)? httpResponse : keepGetting(nextUrl);
});
}
Parse.Cloud.define("myFunc", fucntion (request, response){
// initialize fb_url somehow
keepGetting(fb_url).then(function(result) {
response.success(result);
}, function(error) {
response.error(error);
});
});
(Careful, if the service takes too long or returns too many results before null, your parse call will timeout)

Cant query object by object id

In my cloud code, I'm trying to query an object from Parse.com right after after I save by using the object id. For some reason its not working right and all the other variations of the starred out line I've tried wont work either. What am I doing wrong?
Parse.Cloud.afterSave("NewMessage", function(leanBody, leanSenderName, leanSenderId, request) {
var query = new Parse.Query("NewMessage");
query.get(request.object.id, { *************************************************
success: function(results) {
console.log("The first object was retrieved");
leanBody = (results.get("MessageBody"));
leanSenderName = (results.get("senderName"));
leanSenderId = (results.get("senderId"));
getUsers(leanBody, leanSenderName, leanSenderId);
results.destroy({
success: function(results) {
console.log("deleted");
}, error: function(results, error){
}
});
}, error: function(error){
}
});
});
Do you have ACL set up for the messages? You may need to use the masterKey.
Parse.Cloud.useMasterKey();

Categories

Resources