I use parse.comas backend service for my iOSapp. I was trying to do everything in objective-c since I don't have any experience with JavaScript, but turns out I will need to develop some Cloud Code Functions in JavaScript to complete my app.
A simple routine I'm trying to create:
User retrieves an object using a Cloud Function.
User saves another object in a different class.
An afterSavefunction runs in the cloud to update object first retrieved.
Now, here is my code:
var UserConfigOrientador = Parse.Object.extend("UserConfigOrientador");
var query = new Parse.Query(UserConfigOrientador);
Parse.Cloud.define('pegarOrientadorLivre', function(request, response) {
Parse.Cloud.useMasterKey();
query.greaterThan("entrevistasDisponibilidade", 0);
query.first({
success: function(results) {
response.success(results);
query = results;
},
error: function(error) {
response.error('Favor, checar rede e tentar novamente.');
}
});
});
// AfterSave
Parse.Cloud.afterSave("Agenda", function(request) {
Parse.Cloud.useMasterKey();
query.set("entrevistasDisponibilidade", 70);
query.save();
}
});
});
Now, the second function is not working, I'm getting the message that Object has no set method.
Basically, my questions are:
How can I share data between functions?
Should I keep everything in main.js or can I use another file?
I'm using webStorm for development. And the question about main.js is that after a while I will have a lot of functions and I am trying to figure out how to organize my code.
Your issue is one of scope, and poorly named variables that you're reusing for multiple purposes.
You define your query variable as a query, use it, but inside the success handler you set it to the result of the query (you now have a variable called query which is actually an instance of your UserConfigOrientador class).
When that Cloud Code finishes running, the result goes out of scope and is most likely set to undefined. You shouldn't be trying to share variables between multiple Cloud Code methods like that.
Is there something on the Agenda object that can let you know which UserConfigOrientador to update? Perhaps you could add a pointer property to the UserConfigOrientador? If you did, then you could use the following:
// AfterSave
Parse.Cloud.afterSave("Agenda", function(request) {
Parse.Cloud.useMasterKey();
var userConfigOrientadorQuery = new Parse.Query("UserConfigOrientador");
// read "userConfigOrientador" pointer property on "Agenda" object
var userConfigId = request.object.get("userConfigOrientador").id;
userConfigOrientadorQuery.get(userConfigId, {
success: function(userConfigOrientador) {
userConfigOrientador.set("entrevistasDisponibilidade", 70);
userConfigOrientador.save();
}
});
});
Mm.. I don't think it quite works the way you expect.
When your Cloud code runs, your initial var query declaration is indeed available within the scope of your cloud function and afterSave function. However, you're not passing it in correctly. As a matter of fact, I'm a little confused because your query seems to be requesting a UserConfigOrientador object while your afterSave is on an Agenda object.
So there are two different things going on here. Since you don't actually save an agenda object, I'm assuming that your response.success() returns a JSON of the UserConfigOrientador object back to client side at which point you do some manipulation then save the Agenda object based on that result.
At this point, when you save() the Agenda object now the afterSave() function will run but your query value will be the var query = new Parse.Query(UserConfigOrientador); which does not have a set method. This is why you get the error.
I'm not even sure your query = results; line will actually execute as you should be calling it at the END of your sub-routine and it signals to Parse that it is the end.
If you can tell me how you're saving the Agenda object I can probably complete the picture.
EDIT: --- abstracted but maybe this is the pattern you're looking for...
var ObjectA = Parse.Object.extend('ObjectA');
var queryObjectA = new Parse.Query('ObjectA');
Parse.Cloud.define('findObjectX', function(request, response) {
Parse.Cloud.useMasterKey();
// other query options here...
query.first({
// the first() function will return a Parse.Object
success: function(objectX) {
// Now you have objectX
// Now you want to save some other object
var otherObj = new ObjectA();
// Do things to otherObj
otherObj.save({
success: function(result) { // will be the saved otherObj
// Now you do stuff to your queried obj and save
objectX.set('something', result); // or whatever
// Note, it accomplishes what I think you want without afterSave()
}
}); // async... but we can just let this guy go
},
error: function(error) {
response.error('Favor, checar rede e tentar novamente.');
}
});
});
Related
I have a script updating a MongoDB collection and log the error and result object in its callback function. Every works fine except the result object contains a long chunk of code, which I have no idea how to get rid of. I'm using native MongoDB node.js driver, version 2.0.46.
Code snippet:
var find = {_id:id}, set = {$set:{dt:now}};
myCollection.update(find, set, function(err, result) {
if(err) logger.error(JSON.stringify([find, set]), err.toString());
else logger.verbose(result);
})
I then receive this set of log entry when no error occurs for the update.
2015-10-29T03:45:13.253Z - verbose: ok=1, nModified=1, n=1, _bsontype=Timestamp, low_=17, high_=1446090311, _bsontype=ObjectID, id=V.ßÂb$#\¾¾«, domain=null,
close=function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
The function you see in the log entry above is just a small part. The actual "close function" is tens of thousands lines long, so it fills up my log files quickly.
The logger I'm using is Winston.
I'm wondering what I have done wrong to cause such a return? Any advice is appreciated.
This is not mongodb or native mongodb driver issue.
MongoDB result contains the other details regarding database and row so you are receiving the method in the console.
You need to log the information which you need by accessing the objects available in result object i.e result.ok, result.n, result.nModified
something like below,
winston.info(result.ok, result.n, result.nModified);
I have a simple function which routes a HTTP query pattern, queries redis and sends a response. The following is the code
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname,function(err,obj){
console.log("the response from redis is ",obj)
cache.put(eventname,obj);
console.log("inserting to cache");
this.res.end(obj); // this object is root cause for all problems
});
}
The router object afaik, sends the response using this.res.end(obj) . I guess since I am trying to do this inside my redis client , I am getting error. Is there any other way to send the value as a response ? I thought of using emitter based model where the channel emits the response and listener gets it. but it feels like a round about way to solving this problem. Is there any simpler approach ?
The error may be because, where you're trying to use this, it doesn't have the intended value -- an object with a res property that in turn has an end() method.
That would be because every function in JavaScript has its own this with its own value. And, when nesting functions, using this will return the value for the closest function (i.e. shadowing).
To resolve that, you can save the intended value to a local variable:
router.get('/getinfo/:teamname', function main(teamname) {
var request = this;
rclient.hgetall(teamname,function(err,obj){
// ...
request.res.end(obj);
});
});
Or, bind the anonymous callback so both functions are forced to have the same this value:
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname, function(err,obj){
// ...
this.res.end(obj);
}.bind(this));
});
I'm trying to store all returned objects into one object for later use. I have the loop set in place but when I try to execute some code with the new object, its empty. In this case here alert the object. I guess the alert is executing before the loop is complete. Any way to fix this?
var followers = new Array;
Parse.initialize("xxxxxx", "xxxxx");
var currentUser = Parse.User.current();
var users = JSON.stringify(currentUser);
var user = eval("(" + users + ")");
var listsfollow = user.Follow;
for (var i = 0; i < listsfollow.length; i++) {
var allUsers = Parse.Object.extend("User");
var query = new Parse.Query(allUsers);
query.get(listsfollow[i], {
success: function (results) {
followers.push(results);
},
error: function (object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and description.
}
});
};
alert(followers);
You are correct and the AJAX stuff in jquery is async, and so the .get() will happen after the alert. The quickest and dirtiest way would be to set it to an async to false before issue the request: http://api.jquery.com/jQuery.ajax/
A better way would be to have your code respond to the result of the call whenever it is ready. This will prevent page blocking and make your code faster.
This is an asynchronous query, and the alert is being shown right after the query has initiated, so it's unlikely that it will be executed after the query has returned any results.
Any code that depends on the query's results should be moved into either the success or error callback functions.
I couldn't figure out how to make it wait for the query but I used this to do something after the last loop iteration. Worked great.
if((--remaining)==0)alert(followers);
I have a namespace object on which I have defined some functions. One of the functions is used to create a websocket session to a remote server.
ns.Session = function(url, config, callback){
var ws = new WebSocket(url);
ws.onmessage = function (e){
if(login(e.data)){
// This is the point at which I need to pass back the session object to callback
callback(session):
}
}
....
}
In Javascript, as far as I know if someone invokes this function using ns.Session(....) then the this object will be ns. So, how do I get the instance of the "session" to send to the callback.
arguments.callee is deprecated as far as I know.
The whole reason I am doing it this way is that the session is not considered "usable" till the server confirms the login, so I don't want to prematurely return the function object before it is actually connected and logged in. Hence the use of a callback. If there is a better way to achieve this, I am open to that too.
Session has a bunch of other inner functions like addHandler, sendData etc which I have not shown here for sake of brevity.
You can use pointer to function like this:
ns.Session = function session(...) {
// 'session' here points to your function, so you do
callback(session); // like you wrote
callback(ns.Session); // same effect if you don't change ns and ns.Session pointers
}
Also, I don't see why you use the word "instance" in this case, because functions have only one instance. If you call it with the 'new' keyword, function creates new object from the function, and now there you can use "instance" word.
I'm using Node.js + Express + nodejs-sqlite3 to make a form that when submited will insert a new row on an slite3 database.
On query sucess I want to write certain response.
So the small big problem is just: Modify a string that will be storing the html to be shown, inside the callback function of sqlite3.run()
I read about closures, and passing an object with methods to modify its own attributes. But it seems it's not working. It will pass the object attributes and methods, but no change will remain when the callback function ends. I read that objects will be passed as reference, not copies.
This is the code:
app.post("/insert.html", function(req, res){
function TheBody(){
this.html = "";
this.msg = "";
this.num = "";
}
TheBody.prototype.add = function(string){
this.html = this.html + string;
}
var body = new TheBody();
body.msg = req.body.message;
body.num = req.body.number;
var insertCallback = function(data){
return function(err){
if( err != null){
console.log("Can't insert new msg: " + err.message);
data.add("ERROR-DB");
} else {
console.log("Ok. Inserted: " + data.msg);
console.log(data.html);
data.add("OK - MSG: "+data.msg+" NUM: "+data.num);
console.log(data.html);
}
};
};
var db = new lite.Database('database.db');
var query = "INSERT INTO outbox (message, number) VALUES (?, ?)";
db.run(query, [body.msg, body.num], insertCallback(body) );
res.setHeader('Content-Type', 'text/html');
res.setHeader('Content-Length', body.html.length);
res.end(body.html);
}
On server side I'll see
Ok. Inserted: TestString
[Blank space since data.html still has no information]
OK - MSG: TestString NUM: TestNumber [Showing that indeed was modified inside the function]
But on the client side res.end(body.html); will send an empty string.
The object is not being passed as reference.
What's missing in the code, and what simpler alternatives I have to change a string variable inside a callback anonymous function?.
I already know I could use response.write() to write directly on the function if it were more simpler. But I discovered it would only work if I use response.end() inside the callback, otherwise (being outside as it is now) it will meet a race condition where the buffer will be closed before sqlite3.run() be able to use response.write().
-------- Answered --------
As hinted by Justin Bicknell and confirmed by George P. Nodejs-sqlite3 functions are run asynchronously. So I was ending the stream to the client before the callback would be called, thus nothing was being printed.
This was a problem more about "This is SPART- nodejs, so write your stuff according to events'" rather than a logic one. I found this kind of programming kind of convoluted but nobody else than me told me to use nodejs. For those wondering about how one could put some order over the order of queries on the database, nodejs-sqlite3 functions returns a database object that is used to chain the next query.
Since I was printing the information to the client just once in every handled event, the resulting object ended like this:
function TheBody(response){
this.response = response;
}
TheBody.prototype.printAll = function(string){
this.response.setHeader('Content-Type', 'text/html');
this.response.setHeader('Content-Length', string.length);
this.response.end(string);
}
Preferring that to clutter all the code a lot of res.setHeader() lines.
node-sqlite3 methods are, by default, run in parallel (asynchronously). That means that your code is going through this timeline:
Your code calls db.run(...)
Your code calls res.end(...)
db.run completes and calls your callback.
This is the source of a huge number of questions here on SO, so you can almost certainly find a better answer than anything that I could write here in a reasonable amount of time.
I would start here: How does Asynchronous Javascript Execution happen? and when not to use return statement?