I wrote the following module which connects to postgresql or SQLServer depending a the Type var value:
exports.GetQueryResult = function (type, Name,con,callback) {
var sql='';
if (Type ='PG') {
sql=sql + ' SELECT …………..';
pg.connect(con, function(err, client, done) {
if(err) {
console.log("Error :" + err);
return callback(err);
}
client.query(sql,[Name], function(err, Result) {
if(err) {
console.log("Error: " +err);
return callback(err);
}
return callback(null,Result);
done();
});
});
}
else
{
sql=sql + ' SELECT …..';
sql.open(con, function (err, conn,done) {
if (err) {
console.log("Error :" + err);
return callback(err);
}
conn.queryRaw(sql,Name, function (err, Result) {
if (err) {
console.log("Error ejecutando la consulta. Error: " +err);
return callback(err);
}
callback(null,Result);
done;
});
});
}
};
I call this function from:
var MultiBD = require('./MultiBD.js');
var LayerType=['PG','SQL','PG'];
var con=’’;
for (var i=1; i<=Layers.length; i++) {
if (Layers[i-1]!=undefined){
con=MultiBD.conexion(LayerType [i-1],server,BD);
MultiBD.GetQueryResult(LayerType[i-1], Name[i-1],con,
function (err,Result){
console.log('Result : ' + Result.rows.length);
}
);
}
}
The results are:
Result : 111
Result : 2888
Result : 5
I get three query results. The first one returns 111 rows, the second one 2888 and the third one 5.
What i need is to get only one unique result with all the 3004 rows (111+2888+5).
Regards,
You'll need some flow control to wait until all 3 methods have completed their DB calls before printing their results. There are packages for this, either of the callback variety or Promises.
Here is an example using the async package (which is of the callback variety of flow-control):
var async = require('async');
var totalResults = 0;
async.each( Layers, function eachMethod( layer, eachCb ){
var con = MultiBD.conexion(layer,server,BD);
MultiBD.GetQueryResult(LayerType[i-1], Name[i-1],con, function (err,Result) {
if( err ) return eachCb( err );
totalResults += Result.rows.length;
eachCb( null );
} );
}, function finalEach( eachErr ){
if( eachErr ) console.log( "There was an error. " + eachErr );
else console.log( "Result: " + totalResults );
});
In this call, a method (the eachMethod) is called on every item in the array. The results are stored in a shared variable. When all items have completed, the finalEach method is called. Here errors have bubbled up (which you can choose to check or not) and all calls have completed, so we can simply print the value of the shared variable.
Related
I am making a series of database calls, and want to return something once they have all executed.
I am using the async module to help with this and applying a function to each element in an array.
async.each(items, sqlCall(),
function(err) {
if( err ) {
// All processing will now stop.
console.log('A call failed');
} else {
console.log("finished async operations");
}
});
I define sqlCall as follows
sqlCall = function(item , callback){
console.log("arr is " + JSON.stringify(item));
lampInfo = item[0];
userRoom = item[1];
sql = item[2];
console.log('sql is ' + sql);
connection.query(sql, function(error, results, fields) {
if (error){
console.log("why error");
callback(error);
}
else {
console.log("successful call");
lampSavingsStatement[savingsCalc(lampInfo, results[0], energyPrice)] = userRoom;
callback();
}
});
}
lampSavingsStatement is a global dictionary and savingsCalc is another method
I keep getting a reference error, where arr is undefined, and am not sure what the problem is.
For an example of what items is
[ [ { lampName: '2ft T5 14W', number: '12', hours: '3' },
'room2',
'SELECT * FROM `lightstoled` WHERE `techid` = \'2ft T5 14W\'' ] ]
You are passing to async.each the result of sqlCall(), not the function.
Try this instead:
async.each(items, sqlCall, function (err) { ... });
i am new in node.js and postgresql. am allready connected with postgres db and execute some test code. after am going to use prepared statements.am create a sample login script. if user exist it return username else return message "invalid username or password". if username and password is correct,it return username. but no data will present , then could not return message. my openion is that , the control will crashed after executing cliend.end() function.
this is my code
UserLogin.get = function(userName, callBack) {
pg.connect(pgConString, function(err, client, done) {
if (err) {
callBack("DB connection failed. " + err, null);
return;
}
var selectQuery="SELECT * from " + TABLE + " WHERE userName=($1)";
var query=client.query({
text:selectQuery,
values:[userName],
name:"selectQuery"});
query.on("error", function (error) {
callBack("DB fetch failed. Error Message: " + err, null);});
query.on('row', function(row) {
callBack(null, row);});
query.on("end", function (result) {
client.end();
return;
});
});
}
if row is empty, not return to callback. if row_result is not empty, its working fine.. How...???? any idea...???
finally i got the answer. thanks for u r supports
UserLogin.get = function(userName, callBack) {
pg.connect(pgConString, function(err, client, done) {
if (err) {
callBack("DB connection failed. " + err, null);
return;
}
var selectQuery="SELECT * from " + TABLE + " WHERE userName=($1)";
var query=client.query({
text:selectQuery,
values:[loginId],
name:"selectQuery"});
query.on("error", function (error) {
callBack("DB fetch failed. Error Message: " + err, null);return;});
query.on('row', function(row,result) {
result.addRow(row);
});
query.on('end', function (result) {
callBack(null,result.rows);
client.end();
return;
});
});
}
in my old code, callback will be called everytime the query fetches 1 row from the database. am just changed the logic
Your code
query.on('row', function(row) {
callBack(null, row);
});
means that the callback will be called everytime the query fetches 1 row from the database. In the case when the query has 0 results, the callback will never be called.
I am mew to node js, I have something like this,
get_contacts(data, function(contacts) {
if (contacts.length) {
var count = contacts.length;
for (var i = 0; i < count; i++) {
result = {
id: contacts[i].id,
name: contacts[i].name,
sent1: get_sent(data.userId, contacts[i].id, function(resp) {
result.sent = resp.count;
}),
}
result1[i] = result;
}
output = {
contacts: result1,
}
} else {
output = {
error: "No Contacts.",
}
}
res.writeHead(200, {'content-type': 'text/html'});
res.end(JSON.stringify(output));
});
get_contacts is a callback function which will return contact list.result1 & result are objects. Now value for sent should come from a function get_sent, and get sent is like this
function get_sent(userId, contactId, callback) {
pool.getConnection(function(err, connection) {
connection.query("my query here", function(err, rows) {
connection.release();
if (!err) {
callback(rows);
} else {
console.log(err)
}
});
});
}
But im not getting any value since nodejs. since nodejs is async it is not waiting for the function to return value. I know, im doing it in wrong way. Please help
You need to use a callback. In simple words is a function that you'll execute after something happens. You should read more about that. You should get a book about javascript but you can start reading here for example.
About your case, you could solve it like this
//Asumming that you object `result` is global.
result = {
id: contacts[i].id,
name: contacts[i].name,
sent: -1 //Some default value
}
//Just to put the code into a function, you have to put it where you need
function constructObject (){
get_sent(uId, cId, function(err, total){
if(err){
console.log("Something was wrong.", err);
}
result.sent = total;
//Here you have your object completed
console.log(result);
});
}
//You need to use a callback
function get_sent(uId, cId, callback) {
pool.getConnection(function(err, connection) {
//Note that I add an alias here
connection.query("SELECT count(*) as total FROM table_name", function(err, rows) {
connection.release();
if (!err) {
//I am returning the result of the query and a null error
callback(err, rows[0].total);
} else {
console.log(err);
//I am returning an error
callback(err);
}
});
});
}
//For example you could call this function here
constructObject();
And it depends of what are you doing exactly but Maybe you need a callback on your constructObject too.
I am quite newbie with node.js. What i am trying to achieve is the following:
Connect to my postgresql database and get info of a place (id, coordinates).
call a weather api and get the info of that spot using the coordinates obtained in the previous step.
Insert the returned json in the database. I get 8 hourly objects, with the weather info every 3 hours (0,3,6,9,12,15,18,21). I need to iterate through this objects and the store them in 8 records in the database.
I wrote the following code:
app.get('/getapi', function(req, res){
var json_bbdd;
//------------ BBDD CONNECTION----------------
var pg = require('pg');
var conString = "postgres://postgres:postgres2#localhost/places";
var client = new pg.Client(conString);
client.connect(function(err) {
if(err) {
console.log('could not connect to postgres');
}
client.query('SELECT * from places where id=3276', function(err, result) {
if(err) {
console.log('error running query');
}
json_bbdd=result.rows[0];
var coords = JSON.parse(json_bbdd.json).coordinates;
var id = json_bbdd.id;
var input = {
query: coords[1] + ',' + coords[0] ,
format: 'JSON',
fx: '',
callback: 'MarineWeatherCallback'
};
var url = _PremiumApiBaseURL + "marine.ashx?q=" + input.query + "&format=" + input.format + "&fx=" + input.fx + "&key=" + _PremiumApiKey + "&tide=yes";
$.ajax({
type: 'GET',
url: url,
async: false,
contentType: "application/json",
dataType: 'jsonp',
success: function (json) {
var date= json.data.weather[0].date;
for (var i=0; i < 8; i++){
var hourly = json.data.weather[0].hourly[i];
var time= hourly.time;
client.query('INSERT into parte (id, date, time) VALUES($1, $2, $3)', [id, date, time],
function(err, result) {
if (err) {
console.log(err);
} else {
console.log('row inserted: ' + id + ' ' + time);
}
});
} // FOR
},
error: function (e) {
console.log(e.message);
}
});
client.end();
});
});
});
The steps 1 and 2 are performed perfectly. The third step, on the other hand, does nothing and it doesn't even throw an error.
I read in this post: node-postgres will not insert data, but doesn't throw errors either that using async module could help but i have no idea how to rewrite the code. I need some help.
Regards,
Aitor
I didn't test your snippet, I can only help you with things which looks bad to my eyes.
It is better not to use jQuery on node server. There is excellent library called request to do remote http requests.
You should better handle database errors because in your example your code will continue after DB error.
You are calling client.end() too early and at the time when you try to insert data to the database a connection is already closed. You have to move client.end() at the end of success and error functions and wait to all callbacks are done.
I think it is also better to use connection pool instead of Client.
You can possibly use JSON type in PostgreSQL to avoid serializing/deserializing JSON data in your code.
Here is revised example(untested). I didn't replace jQuery here, some minor tweaking included.
var pg = require('pg');
var conString = "postgres://postgres:postgres2#localhost/places";
app.get('/getapi', function(req, res, next){
var json_bbdd;
//------------ BBDD CONNECTION----------------
pg.connect(conString, function(err, client, done) {
if(err) {
// example how can you handle errors
console.error('could not connect to postgres');
return next(new Error('Database error'));
}
client.query('SELECT * from places where id=3276', function(err, result) {
if(err) {
console.error('error running query');
done();
return next(new Error('Database error'));
}
json_bbdd = result.rows[0];
var coords = JSON.parse(json_bbdd.json).coordinates;
var id = json_bbdd.id;
var input = {
query: coords[1] + ',' + coords[0] ,
format: 'JSON',
fx: '',
callback: 'MarineWeatherCallback'
};
var url = _PremiumApiBaseURL + "marine.ashx?q=" +
input.query + "&format=" + input.format +
"&fx=" + input.fx + "&key=" +
_PremiumApiKey + "&tide=yes";
$.ajax({
type: 'GET',
url: url,
async: false,
contentType: "application/json",
dataType: 'jsonp',
success: function (json) {
var date = json.data.weather[0].date;
var callbacks = 0;
for (var i=0; i < 8; i++) {
var hourly = json.data.weather[0].hourly[i];
var time= hourly.time;
client.query(
'INSERT into parte (id, date, time) VALUES($1, $2, $3)',
[id, date, time],
function(err, result) {
if (err) {
console.log(err);
} else {
console.log('row inserted: ' + id + ' ' + time);
}
callbacks++;
if (callbacks === 8) {
console.log('All callbacks done!');
done(); // done(); is rough equivalent of client.end();
}
});
} // FOR
},
error: function (e) {
console.error(e.message);
done(); // done(); is rough equivalent of client.end();
return next(new Error('Http error'));
}
});
});
});
});
Ok, now cam up with another problem...i was doubting of creating a new post but i think that maybe could have relation with the previous post.
The aim is to read from the database instead of one place 3 places and do the same process than before for each one.
The code is as follows (with the changes proposed by ivoszz):
app.get('/getapi', function(req, res, next){
//------------ BBDD CONNECTION----------------
pg.connect(conString, function(err, client, done) {
if(err) {
// example how can you handle errors
console.error('could not connect to postgres',err);
return next(new Error('Database error'));
}
client.query('SELECT * from places where id>3274 and id<3278', function(err, result) {
if(err) {
console.error('error running query',err);
done();
return next(new Error('Database error'));
}
var first_callback = 0;
for (var y=0; y<result.rows.length; y++) {
var coords = JSON.parse(result.rows[y].json).coordinates;
var id = result.rows[y].id;
var input = {
query: coords[1] + ',' + coords[0] ,
format: 'JSON',
fx: ''
};
var url = _PremiumApiBaseURL + "marine.ashx?q=" + input.query + "&format=" + input.format + "&fx=" + input.fx + "&key=" + _PremiumApiKey;
request(url, function(err, resp, body) {
body = JSON.parse(body);
if (!err && resp.statusCode == 200) {
var date = body.data.weather[0].date;
var callbacks = 0;
for (var i=0; i < 8; i++) {
var hourly = body.data.weather[0].hourly[i];
client.query(
'INSERT into parte (id, date, time) VALUES($1, $2, $3)',
[id, date, hourly.time],
function(err, result) {
if (err) {
console.log(err);
} else {
console.log('row inserted: ' + id + ' iteration ' + i);
}
callbacks++;
if (callbacks === 8) {
console.log('All callbacks done!from id '+id);
//done(); // done(); is rough equivalent of client.end();
//res.send("done");
}
});
} // FOR
}
else { // if the API http request throws an error
console.error(err);
done(); // done(); is rough equivalent of client.end();
return next(new Error('Http API error'));
}
}); // REQUEST API URL
first_callback++;
if (first_callback === result.rows.length-1) {
console.log('All global callbacks done!');
done(); // done(); is rough equivalent of client.end();
res.send("done");
}}
}); // SELECT from pg
}); // CONNECT to pg
}); // app.get
I don't know why it tries to insert the id=3277 three times instead of inserting id=3275, id=3276 and then id=3277... what it does instead is: it inserts the first 8 records ok the first time (id=3277), but then it throws an error saying that the records are already inserted (primary key=id,date,time) with id 3277...
It seems that first does the 3 iterations of the first FOR and then does the 3 iteration of the second FOR but with the info of the last iteration(place). I can't understand it very well...
Assuming I have the following in a function:
exports.addnames = function(req, res) {
var names = ["Kelley", "Amy", "Mark"];
for(var i = 0; i < names.length; i++) {
(function (name_now) {
Person.findOne({ name: name_now},
function(err, doc) {
if(!err && !doc) {
var personDoc = new PersonDoc();
personDoc.name = name_now;
console.log(personDoc.name);
personDoc.save(function(err) {});
} else if(!err) {
console.log("Person is in the system");
} else {
console.log("ERROR: " + err);
}
}
);
)(names[i]);
}
My issue is after I save the names, I want to return the results:
Person.find({}, function(err, doc) {
res.json(200, doc);
})
Though I have a callback for names, it appears that the last block of code (Persons.find({})) gets executed before the calls to save all the names is complete... thusly when the user goes to the url in the browser, "doc" is empty... Is there some way I can ensure that the Persons.find({}) is called after the for loop completes?
The easiest way to do things like this is to use an async library like the aptly named async which can be found at https://github.com/caolan/async.
If you have a list of names that you want to save and then return when complete, it would look like:
// save each of the names asynchronously
async.forEach(names, function(name, done) {
Person.findOne({name: name},
function(err, doc) {
// return immediately if there was an error
if(err) return done(err);
// save the person if it doesn't already exist
if(!doc) {
var personDoc = new PersonDoc();
personDoc.name = name;
console.log(personDoc.name);
// the async call is complete after the save completes
return personDoc.save(done);
}
// or if the name is already there, just return successfully
console.log("Person is in the system");
done();
}
);
},
// this function is called after all of the names have been saved
// or as soon as an error occurs
function(err) {
if(err) return console.log('ERROR: ' + err);
Person.find({}, function(err, doc) {
res.json(200, doc);
})
});