How to use callback function inside a function? - javascript

I want to call a callback function inside a function.so i don't know how to do that
function call(){
pg.connect(conString, function(err, client, done) {
if(err) {
return console.error('error fetching client from pool', err);
}
client.query('INSERT into post1 (data) VALUES ($n)', function(err, result) {
//call `done()` to release the client back to the pool
done();
if(err) {
return console.error('error running query', err);
}
console.log(result.rows[0].number);
//output: 1
});
});
}
board.on("ready", function() {
// Create a new generic sensor instance for
// a sensor connected to an analog (ADC) pin
var sensor = new five.Sensor("A0");
// When the sensor value changes, log the value
sensor.on("change", function() {
var n = this.value();
//i want to call that function here
});
});
and i also want to call this function in another callback function is this the correct way to do or suggest me the right one.

You could do something like this, where you are passing a function into your function. So callback would be a function in this case.
function call(callback){
pg.connect(conString, function(err, client, done) {
if(err) {
return console.error('error fetching client from pool', err);
}
client.query('SELECT $1::int AS number', ['1'], function(err, result) {
//call `done()` to release the client back to the pool
done();
callback(); //execute here or wherever
if(err) {
return console.error('error running query', err);
}
console.log(result.rows[0].number);
//output: 1
});
});
}
then you could call it like
call(function(){
//some logic here.
})
or:
var someFunction = function()
{
//do something
}
call(someFunction);

Related

Nodejs, close mongo db connection via callback

I have the problem with callbacks, async thinking etc.
Execution program:
Connect to mongoDb.
Create url - https://example.com + add part from locArray.
Send get request (for each).
Save data to mongo db.
Close connection.
Problem:
If the connection was closed on last line in jsonDataFromApi - "server instance pool was destroyed" before all data from each request was saved to db
So callback(db) was sent to another place - closeMongoDb
but error was appeared
"Cannot read property 'close' of undefined".
I think, the problem is with async, send callbacks etc.
const MongoClient = require('mongodb').MongoClient;
const Array = require('node-array');
const request = require('request');
var locationArray = [
'location1',
'location2',
'location3',
'location4'
];
var dataFromLocApi = (loc, callback) => {
request({
url: `https://example.com/${loc}`,
json: true
}, (error, response, body) => {
if (error){
callback('Error connection to url.');
} else{
callback(undefined, body.result);
}
});
};
var jsonDataFromApi = (urldb, callback) => {
MongoClient.connect(urldb, (err, db) => {
if (err) {
console.log('MongoDb connection error.');
}
console.log('MongoDb - connected.');
locationArray.forEachAsync(function(loc, index, arr) {
dataFromLocApi(loc, (errorMessage, results) => {
if (errorMessage) {
console.log(errorMessage);
} else {
console.log(JSON.stringify(results, undefined, 2));
db.collection('testCollection').insert(results, function(error, record) {
if (error)
throw error;
console.log("data saved");
});
}
});
}, function() {
console.log('complete');
});
callback(db);
});
}
var closeMongoDb = (urldb, callback) => {
jsonDataFromApi(urldb, (error, db) => {
if (error){
callback('Close connection - failure');
} else{
db.close();
console.log('MongoDb connections was closed.');
}
});
}
closeMongoDb('mongodb://127.0.0.1:27017/testDb', (err, db) => {
console.log('DONE');
} );
There is definitely a problem with asynchrony there.
You're not waiting for the items to be processed before calling the db.close().
Also, the functions that you have defined have the unclear semantics. For example, the function closeMongoDb should basically close the DB and that's it. But here does the other job: fetches the data and closes the DB afterwards.
Also, I'd probably use the async module instead of node-array as the last one seems to solve other problem.
I've refactored the code. Please read my comments. I tried to make it as clear as possible.
const MongoClient = require("mongodb").MongoClient;
const request = require("request");
// We are going to use the async module
// This is a classical module to handle async behavior.
const async = require("async");
// As you can see this function accepts a callback
// If there is an error connecting to the DB
// it passes it up to the caller via callback(err)
// This is a general pattern
const connectToDb = function(urldb, callback) {
MongoClient.connect(urldb, (err, db) => {
if (err) {
console.log("MongoDb connection error.");
callback(err);
return;
}
// If everything is OK, pass the db as a data to the caller.
callback(undefined, db);
});
};
// This method fetches the data for a single location.
// The logic with errors/data is absolutely the same.
const getData = (loc, callback) => {
request(
{
url: `https://example.com/${loc}`,
json: true
},
(error, response, body) => {
if (error) {
callback("Error connection to url.");
return;
}
callback(undefined, body.result);
}
);
};
// This function goes over each location, pulls the data and saves it to the DB
// Last parameter is a callback, I called it allDataFetchedCb to make it clear
// that we are calling it after ALL the locations have been processed
// And everything is saved to the DB.
const saveDataFromLocations = function(locations, db, allDataFetchedCb) {
// First param here is an array of items
// The second one is an async function that we want to execute for each item
// When a single item is processed we call the callback. I named it 'locProcessedCB'
// So it's clear what happens.
// The third parameter is a callback that is going to be called when ALL the items
// have been processed.
async.each(
locations,
function(loc, locProcessedCb) {
getData(loc, (apiErr, results) => {
if (apiErr) {
console.log(apiErr);
// Well, we couldn't process the item, pass the error up.
locProcessedCb(apiErr);
return;
}
console.log(
`Obtained the data from the api: ${JSON.stringify(
results,
undefined,
2
)}`
);
db.collection("testCollection").insert(results, function(dbError) {
if (dbError) {
// Also an error, we couldn't process the item.
locProcessedCb(dbError);
return;
}
// Ok the item is processed without errors, after calling this
// So we tell the async.each function: ok, good, go on and process the next one.
locProcessedCb();
});
});
},
function(err) {
// We gonna get here after all the items have been processed or any error happened.
if (err) {
allDataFetchedCb(err);
return;
}
console.log("All the locations have been processed.");
// All good, passing the db object up.
allDataFetchedCb(undefined, db);
}
);
};
// This function is an entry point.
// It calls all the above functions one by one.
const getDataAndCloseDb = function(urldb, locations, callback) {
//Well, let's connect.
connectToDb(urldb, (err, db) => {
if (err) {
callback(err);
return;
}
// Now let's get everything.
saveDataFromLocations(locations, db, (err, db) => {
if (err) {
callback(err);
return;
}
// If somehow there is no db object, or no close method we wanna know about it.
if (!db || !db.close) {
callback(new Error("Unable to close the DB Connection."));
}
// Closing the DB.
db.close(err => {
// If there's no error err === undefined or null
// So this call is equal to callback(undefined);
callback(err);
});
});
});
};
const locationArray = ["location1", "location2", "location3", "location4"];
// Finally calling the function, passing all needed data inside.
getDataAndCloseDb("mongodb://127.0.0.1:27017/testDb", locationArray, err => {
if (err) {
console.error(
`Unable to fetch the data due to the following reason: ${err}`
);
return;
}
console.log("Done successfully.");
});
I didn't run this code as I don't have the URL etc. So please try it yourself and debug if needed.

How can I execute one query after another and process that data?

I have an app.get that will return customer data and customer purchases. Inside this app.get I need run two mysql calls and build a an array to pass back.
How can I execute one query after another and process that data?
app.get('/customer', function (req,res) {
var response1 = [];
var response2 = [];
var processedData = [];
connection.query('QUERY HERE', function(err, rows, fields) {
if (!err){
response.push({rows});
} else {
res.status(400).send(err);
}
});
//for loop 'response' results and perform another query
for (var i = 0; i < response1.length; i++) {
var row = response1[i];
connection.query('QUERY HERE FOR row.customerid', function(err, rows, fields) {
if (!err){
processedData.push({'Customer Name:' : row.customername, 'purchases' : rows});
} else {
res.status(400).send(err);
}
});
}
//Send json back
res.setHeader('Content-Type', 'application/json');
res.status(200).send(JSON.stringify(processedData));
});
There is a very convenient module called async.js that provides a bunch of functions for doing complex async operations. Particularly,
async.waterfall() is great when you need to pass down results from one async operation/task to another.
async.mapSeries() is great when you need to create a new array with results from an array of async operation/tasks.
Let's use both.
If I understood your code correctly, the code would look something similar to
app.get('/customer', function (req, res) {
async.waterfall([
// each task is passed a callback 'cb' as last argument;
// you MUST call it at least and at most once within each task;
// if you pass an error into the callback as the first argument, it will stop the async function
function task1 (cb1) {
//connection.query('QUERY HERE', function(err, rows, fields) {
// if (err) return cb1(err); // stop waterfall() if an error occurred
// cb1(null, rows, fields); // pass results down to next task
//});
connection.query('QUERY HERE', cb1); // shorter version
},
function task2 (rows, fields, cb2) {
// iterate and run async operation over each element in array 'rows'
async.mapSeries(rows, function getPurchases (row, cb3) {
connection.query('QUERY HERE FOR row.customerid', function (err, purchases, fields) {
if (err) return cb3(err); // stop mapSeries() if an error occurred
cb3(null, { 'Customer Name': row.customername, 'purchases': purchases })
});
}, function (err, customers) {
// when mapSeries() is done iterating OR if an error occurred, it will come here
if (err) return cb2(err); // stop waterfall() if an error occurred
cb2(null, customers)
});
// }, cb2); // shorter version
}
], function (err, customers) {
// when waterfall() is done all its tasks OR if an error occurred, it will come here
// handle error and send response here
});
});

How to get data from a different node.js code

I have a code snippet in the db.js as below,
exports.asyncGetAllData = function () {
connection.connect(function(err) {
connection.query(sqlGetAllData, function (err, result) {
if (err) reject(err);
else
{
//console.log(result);
}
});
});
};
And I want to get the result data when I called the function in app.js as below.
app.get('/test/getPriceTrend', function(req, res) {
console.log('SERVER::getPriceTrend');
console.log(req.url);
var data = db_connection.asyncGetAllData(); //data is undefined
console.log(data);
res.setHeader('Accept', 'application/json');
res.writeHead(res.statusCode);
//The following piece of code will send information from the database
res.write(JSON.stringify({"hello":"world"}));
res.end();
});
As you can see, when I tried to fetch data from db.js, it shows in the console window "the data is undefined". How can I solve this issue? Any suggestion?
Thanks in advance,
Looks like you are calling for data using async method and not waiting for the response.
var data = db_connection.asyncGetAllData(); //data is undefined
console.log(data);
Either use a function that would get you SyncData or use a callback as in:
exports.asyncGetAllData = function (cb) {
connection.connect(function(err) {
connection.query(sqlGetAllData, function (err, result) {
if (err) reject(err);
else
{
//console.log(result);
cb(data);
}
});
});
};
var data = db_connection.asyncGetAllData(function(data) {
console.log(data);
res.write(JSON.stringify(data));
res.end();
});
The easiest way to do this is to create a callback function that you pass to asyncGetAllData()
Your function would look more like this:
exports.asyncGetAllData = function (callback) {
connection.connect(function(err) {
connection.query(sqlGetAllData, callback)
})
}
Then in you app.js you pass the callback in:
db_connection.asyncGetAllData(function(err, result{
if (err) reject(err);
else
{
//console.log(result);
}
})
You could also adjust asyncGetAllData to return a promise,which might make things a little prettier.

Manage many connections from nodejs to postgres with pg

I want to execute a script that will perform a lot of queries and I use pg to manage the connections. The problem is that when my pool is full, my program stops and doesn't queue the future queries. I try to set the poolSize at 0 but it doesn't work either.
pg.defaults.poolSize = 100000000;
var pgQuery = function(query) {
return new Promise(function(resolve, reject) {
pg.connect(conString, function(err, client) { // When the pool is full, pg doesn't connect to the DB
if(err) {
console.error('error fetching client from pool', err);
reject(err);
}
client.query(query,
function(err, res) {
if(err) {
console.error('error running query', err);
reject(err);
}
resolve(res);
});
});
});
};
Any suggestions?
I found my problem, I wasn't releasing the clients back to the pool. For this I had to call the done() callback after my query was executed.
var pgQuery = function(query) {
var attempt = 0;
return new Promise(function(resolve, reject) {
// I added the done callback in parameter.
pg.connect(conString, function(err, client, done) {
if(err) {
console.error('error fetching client from pool', err);
attempt++;
if (attempt < 11) {
pgQuery(query);
} else {
reject(err);
}
}
client.query(query,
function(err, res) {
//call `done()` to release the client back to the pool
done();
if(err) {
console.error('error running query', err);
reject(err);
}
resolve(res);
});
});
});
};
Also my request is cpu intensive and takes a long time to execute. Because of that my request was called twice, I fixed this with
// Without this line the http request is triggered twice
req.connection.setTimeout(15*60*1000)

My callbacks are wrong - I am returning my response to my error object - Nodejs

I am trying to learn node and understand how callbacks are working. I am doing this by trying to use the async lib. I am trying to hit my db with 2 separate calls and use the async lib to let me know when my object is ready to build. Here is my aysnc code:
async.parallel({
one: function(callback) {
getUser(id, callback);
},
two: function(callback) {
getUserServices(id, callback);
}
}, function(err, results) {
if(err) {
console.log(err);
new Error();
}
res.json(result);
});
Here are what my functions look like where I am calling the db. There are both basically the same function:
var getUser = function(id, callback) {
var query = client.query('SELECT * FROM USERS WHERE USER_ID=$1', [id]);
query.on('row', function(row, result) {
result.addRow(row);
});
query.on('end', function(result) {
callback(result);
});
};
My code hits the db and returns the user, but when it goes back up to the async code the user is in the err object. What am I doing wrong? How do I properly set up callbacks?
As pointed by damphat, your code should be
//additionally, handle errors
query.on('error', function(err){
callback(err) // The first argument to callback should be an error object
})
query.on('end', function(result){
callback(null, result) //passing null error object
})

Categories

Resources