I am new to nodejs and am writing some code that needs to query my MySQL database and return a username from a given user_id. I've been reading that all your functions should be asynchronous. In this case, ideally I would like the server to be able to respond to other event requests while this query is taking place. However, it isn't a particularly large query and only returns a single value. Maybe I should make it synchronous? (If that is your answer, sample code to change it would be great) Anyways, here is my function. It gives an error near the last line "return current_username;" because current_username is undefined at that point. Any suggestions?
function get_current_username(current_user_id) {
console.log(' | Entered get_current_username');
sqlq = 'SELECT username FROM users WHERE id = ' + current_user_id;
connection.query(sqlq, function(err, rows, fields) {
if (err) throw err;
var current_username = rows[0].username;
console.log(' | the current_username =' + current_username);
});
return current_username;
}
Pass in a callback function to get_current_username and then call that callback function from inside of connect.query's callback:
function get_current_username(current_user_id, callback) {
console.log(' | Entered get_current_username');
sqlq = 'SELECT username FROM users WHERE id = ' + current_user_id;
connection.query(sqlq, function(err, rows, fields) {
if (err) throw err;
var current_username = rows[0].username;
console.log(' | the current_username =' + current_username);
callback(current_username);
});
}
When you go to use this function then, you'd do something like:
get_current_username(12345, function(username) {
console.log("I am " + username);
});
You could also check out the use of promises/futures. I have a feeling I won't be able to do an explanation of these justice, so I'll link off to this StackOverflow question about understanding Promises.
This is an architectural decision though - some people would prefer to use callbacks, especially if writing a module intended for re-use by 3rd parties. (And in fact, it's probably best to get your head fully wrapped around callbacks in the learning stages here, before adopting something like Promise.)
Related
I come from a Python background and have very little JavaScript experience, so I'm a little bit out of my element here.
I'm trying to do something seemingly simple, get an AWS account ID and store it in a variable. I'm referencing the code from this StackOverflow question but I've modified it a bit.
var account = sts.getCallerIdentity({}, function (err, data) {
if (err) {
console.log("Error ", err)
} else {
account = data.Account.toString();
console.log(account);
return account
}
});
//console.log(account);
If I leave the console.log statement commented out, I see the AWS account ID being printed to the console, which is what I'm expecting. However, if I uncomment the line, I get a very big object (which I assume is actually the data variable) that is being printed to the console.
I just want the account variable to be equal to the account ID. What am I doing wrong here?
The function is async so you cant really assign the value. The value gets resolved in the callback at some time in the future. By this point the console.log has already executed.
You can do 2 things, add your logic that requires account in the callback or use promises.
sts.getCallerIdentity({}).promise().then((data) => console.log(data));
sts.getCallerIdentity({}, (err, data) => {...stuff});
Remember these values are resolved sometime in the future.
The account variable won't get set with the data you need until the callback is run. Perhaps try something like this?
var account = sts.getCallerIdentity({}, function (err, data) {
if (err) {
console.log("Error ", err)
} else {
account = data.Account.toString();
doOtherStuff();
}
});
function doOtherStuff() {
console.log(account);
}
I have been going around in circles with this. I'm trying to execute an existing stored procedure using the node js documentdb library.
var sproc = self.client.queryStoredProcedures(collection._self, "select * from root r WHERE r.id = 'helloWorld'");
self.client.executeStoredProcedure(sproc._self, function (err, res) {
if(err){
console.log(err);
}else{
console.log(res);`
}
});
Not entirely sure queryStoredProcedures (Seems to be no async version of this) is the correct way of retrieving the uri for the store procedure, I haven't managed to get this to work. I'm also trying to avoid too many round trips to the database, but from what I gather I either hard code the store procedure's uri or have to make at least two requests just to execute the stored procedure.
queryStoredProcedures (along with all query and read functions) return a QueryIterator rather than an actual result. The methods you call on the returned QueryIterator are async. So, following the approach of your example (minus error handling), you would do this:
var queryIterator = self.client.queryStoredProcedures(collection._self, "select * from root r WHERE r.id = 'helloWorld'");
queryIterator.toArray(function(err, result) {
var sproc = result[0];
self.client.executeStoredProcedure(sproc._self, function (err, res) {
console.log(res);`
});
});
However, since the introduction of id-based routing, you can short hand the above like this:
var sprocLink = "dbs/myDatabase/colls/myCollection/sprocs/helloWorld";
self.client.executeStoredProcedure(sprocLink, function (err, res) {
console.log(res);`
});
I am trying to write a javascript file in express to talk to a postgresql database. More precisely, I want to write a function that takes SQL as an input parameter and returns the stringified json. I can assume memory is not an issue given these table sizes. This is paid work making an internal use tool for a private business.
My most recent attempt involved the query callback putting the value into a global variable, but even that still fails because the outermost function returns before the json string is defined. Here is the relevant code:
var dbjson;
function callDB(q) {
pg.connect(connectionString, function(err, client, done) {
if (err) {
console.error('error fetching client from pool', err);
} else {
client.query(q, [], function(err, result) {
client.query('COMMIT');
done();
if (err) {
console.error('error calling query ' + q, err);
} else {
dbjson = JSON.stringify(result.rows);
console.log('1 ' + dbjson);
}
console.log('2 ' + dbjson);
});
console.log('3 ' + dbjson);
}
console.log('4 ' + dbjson);
});
console.log('5 ' + dbjson);
}
The SQL in my test is "select id from users".
The relevant console output is:
5 undefined
GET /db/readTable?table=users 500 405.691 ms - 1671
3 undefined
4 undefined
1 [{"id":1},{"id":2},{"id":3},{"id":4}]
2 [{"id":1},{"id":2},{"id":3},{"id":4}]
Why do the console logs occur in the order that they do?
They are consistent in the order.
I attempted to write a polling loop to wait for the global variable to be set using setTimeout in the caller and then clearing the timeout within the callback but that failed, I think, because javascript is single threaded and my loop did not allow other activity to proceed. Perhaps I was doing that wrong.
While I know I could have each function handle its own database connection and error logging, I really hate repeating the same code.
What is a better way to do this?
I am relatively new to express and javascript but considerably more experienced with other languages.
Presence of the following line will break everything for you:
client.query('COMMIT');
You are trying to execute an asynchronous command in a synchronous manner, and you are calling done(), releasing the connection, before that query gets a chance to execute. The result of such invalid disconnection would be unpredictable, especially since you are not handling any error in that case.
And why are you calling a COMMIT there in the first place? That in itself looks completely invalid. COMMIT is used for closing the current transaction, that which you do not even open there, so it doesn't exist.
There is a bit of misunderstanding there in terms of asynchronous code usage and the database also. If you want to have a good start at both, I would suggest to have a look at pg-promise.
I'm new at javascript and I've hit a wall hard here. I don't even think this is a Sequelize question and probably more so about javascript behavior.
I have this code:
sequelize.query(query).success( function(row){
console.log(row);
}
)
The var row returns the value(s) that I want, but I have no idea how to access them other than printing to the console. I've tried returning the value, but it isn't returned to where I expect it and I'm not sure where it goes. I want my row, but I don't know how to obtain it :(
Using Javascript on the server side like that requires that you use callbacks. You cannot "return" them like you want, you can however write a function to perform actions on the results.
sequelize.query(query).success(function(row) {
// Here is where you do your stuff on row
// End the process
process.exit();
}
A more practical example, in an express route handler:
// Create a session
app.post("/login", function(req, res) {
var username = req.body.username,
password = req.body.password;
// Obviously, do not inject this directly into the query in the real
// world ---- VERY BAD.
return sequelize
.query("SELECT * FROM users WHERE username = '" + username + "'")
.success(function(row) {
// Also - never store passwords in plain text
if (row.password === password) {
req.session.user = row;
return res.json({success: true});
}
else {
return res.json({success: false, incorrect: true});
}
});
});
Ignore injection and plain text password example - for brevity.
Functions act as "closures" by storing references to any variable in the scope the function is defined in. In my above example, the correct res value is stored for reference per request by the callback I've supplied to sequelize. The direct benefit of this is that more requests can be handled while the query is running and once it's finished more code will be executed. If this wasn't the case, then your process (assuming Node.js) would wait for that one query to finish block all other requests. This is not desired. The callback style is such that your code can do what it needs and move on, waiting for important or processer heavy pieces to finish up and call a function once complete.
EDIT
The API for handling callbacks has changed since answering this question. Sequelize now returns a Promise from .query so changing .success to .then should be all you need to do.
According to the changelog
Backwards compatibility changes:
Events support have been removed so using .on('success') or .success()
is no longer supported. Try using .then() instead.
According this Raw queries documentation you will use something like this now:
sequelize.query("SELECT * FROM `users`", { type: sequelize.QueryTypes.SELECT})
.then(function(users) {
console.log(users);
});
I'm using a NodeJS module called node-github, which is a wrapper around the Github API, to get some statistics about certain users, such as their followers:
var getFollowers = function(user, callback) {
github.user.getFollowers(user, function(err, res) {
console.log("getFollowers", res.length);
callback(err, res);
});
};
...
getFollwers({user: mike}, function(err, followers) {
if(err) {
console.log(err);
}
else {
console.log(followers);
}
});
Apparently, Github limits call results to a maximum of 100 (via the per_page parameter), and utilizes the Link header to let you know a 'next page' of results exists.
The module I'm using provides several easy methods to handle the Link header, so you won't need to parse it. Basically, you can call github.hasNextPage(res) or github.getNextPage(res) (where res is the response you received from the original github.user.getFollowers() call)
What I'm looking for is the right approach/paradigm to having my function return all results, comprised of all pages. I dabbled a bit with a recursive function, and though it works, I can't help but feeling there may be a better approach.
This answer could serve as a good approach to handling all future Link header calls - not just Github's - if the standard catches on.
Thanks!
Finally, resorted to recursion (remember the 2 great weaknesses of recursion: maintaining it, and explaining it :)). Here's my current code, if anyone is interested:
var getFollowers = function(callback) {
var followers = []
, getFollowers = function(error, result) {
followers = followers.concat(result);
if(github.hasNextPage(result)) {
github.getNextPage(result, getFollowers);
}
else {
callback(error, followers);
}
};
github.user.getFollowers(options, getFollowers);
};
But, I found out that if you just need the total number of followers, you can use the getLastPage function to get the number of followers on the last page and then
total_num_of_followers = num_of_followers_on_last_page + (total_num_of_pages * results_per_page)