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
})
})
Related
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);
}
}
});
Note: I have limited exp with js so correct me if my I'm completely wrong in how I'm describing this scenario.
I have two javascript files. I am calling a function on the first file (client side) which calls a function on the second file and uses the callback from the second file's function for the purposes of response.success/.error on the first file.
If that doesn't make sense here is some code:
Note: this is being done temporarily using Parse's cloud functions. Let me know if more information is needed regarding those but not sure if it's important.
First file:
Parse.Cloud.define("methodName", function(request, response) {
...
secondFile.myFunction(param1, {
stuff: request.params.stuff,
}, function (err, res) {
if (err) {
response.error(err);
} else {
response.success(res);// I'm assuming this is going to the hardcoded "yes." from httpRequest on second file's function
}
});
});
Second File:
myFunction: function(param1, properties, callback) {
if (!param1) return callback(new Error("Helpful error message"));
var headersForReq = {
...
};
var bodyForReq = ...; // the properties properly parsed
Parse.Cloud.httpRequest({
method: 'PUT',
url: ...,
headers: headersForReq,
body: bodyForReq,
success: function (httpResponse) {
callback(null, 'yes'); // the hardcoded "yes" i referred to
},
error: function (httpResponse) {
callback(httpResponse.status + httpResponse.error);
}
});
}
On my the client, the code is treated as a success (errors aren't thrown or returned back) but when I print out the value it comes across as (null) not "yes".
What's going on here? (Side note, httpRequest is currently not doing anything, its hard to verify if the request is properly being sent because it's being sent to a third party API).
I do know the second file's method is properly being called though. So it's not a silly issue with the module.exports or var secondFile = require('\path\secondFile')
I think you are just mis-use the api
Rewrite it with the example style.
https://parse.com/docs/js/api/classes/Parse.Cloud.html#methods_httpRequest
Parse.Cloud.httpRequest({
method: 'PUT',
url: ...,
headers: headersForReq,
body: bodyForReq
}).then(function (httpResponse) {
callback(null, 'yes'); // the hardcoded "yes" i referred to
},
function (httpResponse) {
callback(httpResponse.status + httpResponse.error);
}
});
I think below will work, too.
Parse.Cloud.httpRequest({
method: 'PUT',
url: ...,
headers: headersForReq,
body: bodyForReq
}, {
success: function (httpResponse) {
callback(null, 'yes'); // the hardcoded "yes" i referred to
},
error: function (httpResponse) {
callback(httpResponse.status + httpResponse.error);
}
});
BTW, if you are using open source parse-server, you can use request or request-promise. These 2 npm package is used by many people. (Parse.Promise is not es6-like promise)
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
)
});
Im using angular's resource to query some data, the problem is that what the query returns is not this:
[
{"id":"5-w2k93ylznp6tj4i"}
{"id":"6-njzmmwcpkw23ayvi"}
]
its this:
{"id":"5-w2k93ylznp6tj4i"}
{"id":"6-njzmmwcpkw23ayvi"}
instead of getting an array of objects, i get several objects, this makes angular throw this error:
SyntaxError: Unexpected token {
at Object.parse (native)
I think the error is because it does not expect another object. That query is for two items, if i query for just 1 item i get just one object and no error. I suspect that when there are two items, it does not expect a second object and throws the error in the first curly bracket after the first object ends.
Some code:
This is the resource:
list: resource (
'/api/products',
{
limit: '#limit',
skip: '#skip',
sort: '#sort'
},
{
query: {
method: 'GET',
interceptor: {
response: function (data) {
console.log('response in interceptor', data);
},
responseError: function (data) {
console.log('error in interceptor', data);
}
},
isArray: false
}
}
)
Where the resource is used:
factory.loadProducts = function(skip, sort){
var data = Api.Product.list.query(
{
limit: appDataVars.limit,
skip: skip,
sort: sort
}, function(response)
{
appDataVars.productsList = response;
}, function(error)
{
console.error(error);
});
return data.$promise;
};
It always hits the error callback.
My problem is that i cant modify the api, i have to find a way to handle that result set in angular. Any idea how i can achieve that?
Thanks.
Set the query object of the resource to contain a property for transformResponse set to the empty array:
query: {
method: 'GET',
interceptor: {
response: function (data) {
console.log('response in interceptor', data);
},
responseError: function (data) {
console.log('error in interceptor', data);
}
},
isArray: false,
transformResponse: []
}
This will force the response to be treated as a string then change your function that handles the response to be:
function(response)
{
appDataVars.productsList = eval('[' + response.replace(/\n/g, ',') + ']');
}
If the response string is not separated by a newline between objects change it to be response.replace(/}\s*{/g, '},{') (although this is quite a naive regex).
It's a bit hacky, but it should be a workaround since you can't modify the API.
I'm using Backbone.js and using fetch with options, but it doesn't seem to get the error or success callbacks, however data is being returned.
this.user.fetch({data: {username : this.username.val(), check : 'true'}}, {
error: function(model, response) {
console.log(response);
},
success: function(model, response) {
console.log(response);
}
});
This is what I have setup, am I missing something? It never hits error or success, but it does do the ajax request and it's returning data.
Thank you!
You're passing 2 separate arguments to fetch. Combine them into a single object with data, success, and error fields and it should work for you.
Example for x1a4 answer
var myModel = new MyModel({id: modelId});
myModel.fetch({
success: function (model) {
console.log('success: model fetched');
},
error: function () {
console.log('error: loading model');
}
});