Node JS Asynchronous Database Calls - javascript

I am having issues getting node to make a database call without proceeding despite the database function has not returned a value.
Here is the basic http server code:
var http = require('http');
http.createServer(function (request, response) {
response.writeHead(200, {
'Content-Type': 'text/plain',
'Access-Control-Allow-origin': '*' // implementation of CORS
});
response.end("ok");
;
}).listen(8080,'0.0.0.0');
Using the request.on('data') function, I am able to decode JSON from requests and proceed that to make a database call:
request.on('data', function (chunk) {
var json = JSON.parse(chunk);
var id = parseInt(json["id"]);
response.end(callDatabase(id));
});
The database function goes something like this:
function callDatabase(id) {
var result;
var connection = mysql.createConnection(
{
host : '192.168.1.14',
user : 'root',
password : '',
database : 'test'
}
);
connection.connect();
var queryString = 'SELECT name FROM test WHERE id = 1';
connection.query(queryString, function(err, rows, fields) {
if (err) throw err;
for (var i in rows) {
result = rows[i].name;
}
});
connection.end();
return result;
}
}
However under testing, this proves that I am doing it wrong. I am aware that I probably want to be using the node asynchronous module, which I have tired. I have also tried using the waterfall method, as well as parallel and many other tutorials online. I feel that the request.on function should be in parallel, then the database call async, so whilst node is waiting for the response from the database server, it is free to get on with any other requests, leaving the queued time to a minimum.
Please inform me if I have miss-understood any of the concepts of node js.

You are returning result and closing the connection before the query has returned it's value from the db. Place that code inside the callback.
Fixing your code, it should look like this:
function callDatabase(id) {
var result;
var connection = mysql.createConnection(
{
host : '192.168.1.14',
user : 'root',
password : '',
database : 'test'
}
);
connection.connect();
var queryString = 'SELECT name FROM test WHERE id = 1';
connection.query(queryString, function(err, rows, fields) {
if (err) throw err;
for (var i in rows) {
result = rows[i].name;
}
connection.end();
return result;
});
}
Although, this will only solve part of the problem, since now you're still calling response.end(callDatabase(id)); before waiting for a response from the query.
In order to fix this, you need to return some kind of callback.
function callDatabase(id, callback) {
// the method code here...
connection.query(queryString, function(err, rows, fields) {
// code...
// instead of returning the result, invoke the callback!
callback(rows);
});
}
Now you can call it like this :
request.on('data', function (chunk) {
var json = JSON.parse(chunk);
var id = parseInt(json["id"]);
callDatabase(id, function(res) {
response.end(res);
});
});

Related

Pass data from one js file to other synchronously in NodeJS

I have a situation where I need to service function in service folder from my controller folder and once I receive the output I need to pass it back to UI.
//controller
var service = require('service');
api.get('/users', function(request, response) {
var name = request.query['name'];
var responseFromService = service.someAPI(name);
response.send(responseFromService).status(200);
});
//Service
exports.callTwitterAPI = function(twitterHandle,callback){
var responseFromTwitterService;
console.log("Calling Twitter API.." + twitterHandle);
someAPI.get('users/show', {screen_name: twitterHandle}, function (err, data, res) {
if (err) {
//loggerError.error('No connection to twitter :', Date.now());
responseFromTwitterService = JSON.stringify(err) + "Unable to connect twitter";
} else if (data.errors) {
responseFromTwitterService ="User Not Found!!"
// loggerInfo.info('No Twitter handle found for :', twitterHandle);
} else {
console.log("here..");
responseFromTwitterService = data;
}
console.log('response : '+ responseFromTwitterService);
return (null,responseFromTwitterService);
});
}
Now, I need to hold execution of
response.send(responseFromService).status(200);
this line until my service returns response, I need to make it synchronous.
Thanks in advance :)
Your service is going to either be synchronous by nature, or asynchronous by nature, and how you handle it will be determined by that.
If the service call is synchronous, then what you've written will work fine. If it's asynchronous, then you'll just need to send your response in its callback, e.g.:
//controller
var service = require('service');
api.get('/users', function(request, response) {
var name = request.query['name'];
var responseFromService = service.someAPI(name, function(err, responseFromService) {
response.send(responseFromService).status(200);
});
});
//Service
exports.someAPI = function(name, callback){
//some calculations
return callback(null, responseFromService);
}
EDIT after your update
Your service is never calling the callback you declared. Note your last line:
return (null, responseFromTwitterService);
Doesn't actually do anything. Instead you want:
return callback(null, responseFromTwitterService);
And then your calling code in the controller can be written as I suggested.

In Node.js, how to update different components of a page in different frequency?

I'm trying to build a real time webpage to show some real time statistics. This webpage has 12 components. I'm using Ajax in SetTimeout to update each component. Since I'd like to update each component in different frequency, I write a setTimeout function for each component and gives each component a link (defined in "main.js"). Looks like:
(function poll() {
setTimeout(function() {
$.ajax({
url: url1,
type: 'GET',
success : function(info){
var object = document.getElementById("1");
object.textContent = info;
}, complete: poll });
}, 5000);
})();
...
...
(function poll() {
setTimeout(function() {
$.ajax({
url: url12,
type: 'GET',
success : function(info){
var object = document.getElementById("12");
object.textContent = info;
}, complete: poll });
}, 10000);
})();
And in my "server.js", I hope to connect to database only once and then render different components. The configuration of the database will rely on the link so I organize the app like this:
app.get('/:A/:B', function(req,res){
var A= req.params.A;
var B = req.params.B;
var config = something relies on A and B
var client = new pg.Client(config);
client.connect(function(err){
if (err) {
console.log("Error occurred when try to connect the database",err);
}
else {
res.sendFile(__dirname + '/public/main.html');
app.get('/main.js', function(req,res){
res.sendFile(__dirname + '/public/main.js');
});
app.get('/url1',function(req,res) {
//query database and send the data url1 needs
});
...
...
app.get('/url12',function(req,res) {
//query database and send the data url12 needs
});
})
I want to ask if writing "app.get()" within "app.get()" like the code above is good practice. If not, how can I keep a global connection to the database and use it for different components? Also, is there any improvement I can make to this web app? I'm quite new to Node.js
If I had to do this with callbacks instead of promises, this is how I would do it on Server side.
first, I would use your endpoint to get the client, but would put it in a module internal variable, and still send a response if I failed to connect to DB.
var db=null;
app.get('/:A/:B', function(req,res){
var A= req.params.A;
var B = req.params.B;
var config = something relies on A and B
var client = new pg.Client(config);
client.connect(function(err){
if (err) {
console.log("Error occurred when try to connect the database",err);
res.status(503).send("Error connecting to database);
}
else {
db = client;
res.sendFile(__dirname + '/public/main.html');
}
}
}
Then, I would write a function that would reuse that DB if it exists:
function usingDatabase(req,res,next){
if(db) {
req.db=db;
next();
}
else {
res.status(400).send("Bad request. open the DB first by calling /:A/:B");
}
}
finally I'd use it like this:
app.get('/main.js', function(req,res){
res.sendFile(__dirname + '/public/main.js');
});
app.get('/url1',usingDatabase, function(req,res) {
// db is in req.db;
//query database and send the data url1 needs
});
...
...
app.get('/url12',usingDatabase,function(req,res) {
// db is in req.db;
//query database and send the data url12 needs
});

Parse [Error]: success/error was not called (Code: 141, Version: 1.9.0)

I am trying to write a Cloud Code function that will allow me to edit the data of another user as I cannot do that in the application it self. What the code does (I should say tries to do as I don't know JS) is fetch a User object and a Group (a class I created) object using two separate queries based on the two object IDs inputed. Here is my code
Parse.Cloud.define("addInvite", function(request, response) {
Parse.Cloud.useMasterKey();
var userID = request.params.user;
var groupID = request.params.group;
var user;
var group;
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("objectId", userID);
return userQuery.first
({
success: function(userRetrieved)
{
user = userRetrieved;
},
error: function(error)
{
response.error(error.message);
}
});
var groupObject = Parse.Object.extend("Group");
var groupQuery = new Parse.Query(groupObject);
groupQuery.equalTo("objectId", groupID);
return groupQuery.first
({
success: function(groupRetrieved)
{
group = groupRetrieved;
},
error: function(error)
{
response.error(error.message);
}
});
var relations = user.relation("invited");
relations.add(group);
user.save();
response.success();
});
Every time I execute the method I get the error:
[Error]: success/error was not called (Code: 141, Version: 1.9.0)
Can anyone help with this? Thanks.
Every function in Parse Cloud returns a Promise. This also includes any query functions which you run to retrieve some data. Clearly in your code you are returning a Promise when you execute a query which abruptly ends your cloud function when your query completes. As you do not call a response.success() or response.error() in any of the success blocks, your cloud function returns without setting a suitable response, something that Parse requires and hence the error. Your code needs to chain all the promises to ensure your code is executed correctly and return success/error in the last step:
Parse.Cloud.define("addInvite", function(request, response) {
Parse.Cloud.useMasterKey();
var userID = request.params.user;
var groupID = request.params.group;
var user;
var group;
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("objectId", userID);
userQuery.first().then(function(userRetrieved) {
user = userRetrieved;
var groupObject = Parse.Object.extend("Group");
var groupQuery = new Parse.Query(groupObject);
groupQuery.equalTo("objectId", groupID);
return groupQuery.first();
}).then( function(groupRetrieved) {
//group = groupRetrieved;
var relations = user.relation("invited");
relations.add(groupRetrieved);
return user.save();
}).then(function() {
response.success();
}, function(error) {
response.error(error.message);
});
});

How to get asynchronous data using nodejs

I am attempting to get data from a mysql table using nodejs. I call the sql routine which is in another node js file. However, I cannot get my callback to return the data. I think the problem might be that I am calling an asynchronous routine from a node js file rather than from an angular or regular javascript program. Below is the exports script I am calling.
exports.getVenueById = function(db, id) {
var http = require('http');
var mysql = require('mysql');
var query = "SELECT * FROM venues WHERE auto_increment = ? "
query = mysql.format(query, id);
console.log("query=" + query);
db.query(
query,
function(err, rows) {
if(err) console.log("error=" + err);
console.log("rows=" + rows[0]['auto_increment']);
res.json({success: true, response: rows});
//return rows[0];
});
}
I know this is working because I am writing the results to the console. The problem is the data never gets back to the calling node js routine below.
function getVenueData (id , callback) {
(function () {
venueData = venueTable.getVenueById(db, id);
if(venueData) {
callback();
console.log("callback in loop");
}
console.log("callback after loop");
});
}
getVenueData(id, gotVenueData);
The program immediately returns and displays the timeout message. I admit that I am not an expert in nodejs or its callback feature. I would appreciate any feedback as to how I can get the program to wait for the asynchronous data to return to the calling program.
function gotVenueData() {
console.log("gotVenueData");
}
setTimeout(function() { console.log("timeout for 10 seconds");} , 10000);
console.log("venuedata=" + venueData);
You're trying to return async data syncronously. Instead, add a callback to getVenueById:
exports.getVenueById = function (db, id, cb) {
var http = require('http');
var mysql = require('mysql');
var query = "SELECT * FROM venues WHERE auto_increment = ? ";
query = mysql.format(query, id);
console.log("query=" + query);
db.query(
query,
function (err, rows) {
if (err) console.log("error=" + err);
console.log("rows=" + rows[0]['auto_increment']);
cb({
success: true,
response: rows
});
// return rows[0];
});
and use it as such:
venueTable.getVenueById(db, id, function(data) {
console.log(data);
});
One caveat: Traditionally the callback has the first parameter as the error (or null) and then the actual data. With that in mind:
exports.getVenueById = function (db, id, cb) {
var http = require('http');
var mysql = require('mysql');
var query = "SELECT * FROM venues WHERE auto_increment = ? ";
query = mysql.format(query, id);
console.log("query=" + query);
db.query(
query,
function (err, rows) {
if (err) { cb(err); }
console.log("rows=" + rows[0]['auto_increment']);
cb(null, {
success: true,
response: rows
});
// return rows[0];
});
and use it as such:
venueTable.getVenueById(db, id, function(err, data) {
if (err) { return console.log(err); }
console.log(data);
});

NodeJS unable to make a GET request asynchronously

I am a rookie in Nodejs and asynchronous programming. I am having a problem executing a GET request inside an asynchronous function. Here I am posting the whole code. I am trying to pull a list of all Urls , add them to a list and send the list for processing to another function.
My problem is with processing them. Inturn for each url I am executing a GET request to fetch the body and to look for image elements in it. I am looking to pass the Image url to a 3rd party api as a GET param. I am unable to execute the GET request as the control doesn't seem to reach there at all.
var async = require("async"),
request = require("request"),
cheerio = require("cheerio");
async.waterfall([
function(callback) {
var url = "someSourceUrl";
var linkList = [];
request(url, function(err, resp, body) {
var $ = cheerio.load(body);
$('.list_more li').each(function() {
//Find all urls and add them to a list
$(this).find('a').each(function() {
linkList.push($(this).attr('href'));
});
});
callback(null, linkList);
});
},
//pass all the links as a list to callback
function(liksListFetched, callback) {
for (var i in liksListFetched) {
callback(null, liksListFetched[i]);
}
}],
//***********My problem is with the below code**************
function(err, curUrl) {
var cuResp = "";
console.log("Currently Processing Url : " + curUrl);
request(curUrl, function(err, resp, body) {
var $ = cheerio.load(body);
var article = $("article");
var articleImage = article.find("figure").children('img').attr('src');
var responseGrabbed = "API response : ";
//check if there is an IMG element
if (articleImage === undefined) {
console.log("No Image Found.");
articleImage = 'none';
}
else {
//if there is an img element, pass this image url to an API,
//So do a GET call by passing imageUrl to the API as a GET param
request("http://apiurl.tld?imageurl=" + articleImage, function(error, response, resp) { //code doesn't seem to reach here
I would like to grab the response and concatenate it to the responseGrabbed var.
console.log(resp);
responseGrabbed += resp;
});
}
console.log(responseGrabbed);// api response never gets concatenated :(
console.log("_=_=_=_=_=_=__=_=_=_=_=_=__=_=_=_=_=_=__=_=_=_=_=_=_");
process.exit(0);
});
});
I appreciate if any one can help me understand the root cause. Thanks in advance.
request() is asynchronous, so when you're console logging the string, the string hasn't been built yet, you have to do the console log inside the callback :
request("http://apiurl.tld?imageurl=" + articleImage, function(error, response, resp) {
responseGrabbed += resp;
console.log(responseGrabbed);// api response never gets concatenated :(
console.log("_=_=_=_=_=_=__=_=_=_=_=_=__=_=_=_=_=_=__=_=_=_=_=_=_");
});
Same goes for terminating the process, which should be done when all the requests have finished

Categories