Getting Response of a function defined in another file in node.js - node.js

I have a socket function defined as
var funcs = require('./funcs');
socket.on(EVENT_ACCEPT_ORDER, function(data, callback)
{
data = JSON.parse(data);
var bookingId = data.bookingId;
var userId = data.userId;
console.log("Accepting booking...." + bookingId);
var query = "UPDATE bookings SET bookingStatus = " + BOOKING_STATUS_ACCEPTED + " WHERE id = " + bookingId + " AND bookingStatus = " + BOOKING_STATUS_IN_QUEUE;
con.query(query, function(err, rows,fields)
{
if(err)
{
console.log("mysql query error");
}
else
{
if(rows.changedRows > 0)
{
var indexOfUser = usersList.indexOf(userId);
if(indexOfUser > -1)
{
userSockets[indexOfUser].emit(EVENT_USER_ORDER_ACCEPTED);
}
callback({"message": "Success","error":false, "booking": funcs.getBooking(con, bookingId)});
}
else
callback({"message": "Success","error":true});
}
});
});
Funcs is defined as
module.exports = {
"getBooking": function (con, bookingId)
{
var query = "SELECT * FROM bookings WHERE id = " + bookingId + " LIMIT 1";
con.query(query, function(err, rows,fields)
{
if(err)
{
console.log("mysql query error");
}
else if (rows.length == 1)
{
var booking = rows[0];
var userId = rows[0]['userId'];
var query = "SELECT id, name, phone, imagePath FROM users WHERE id = " + userId + " LIMIT 1";
con.query(query, function(err, rows,fields)
{
if(err)
{
console.log("mysql query error");
}
else if (rows.length == 1)
{
booking['user'] = rows[0];
return booking;
}
});
}
});
}
}
Everything is running fine except
callback({"message": "Success","error":false, "booking": funcs.getBooking(con, bookingId)});
in this function instead of booking, i am only getting
{"error":false,"message":"Success"}
Why am i not getting the booking function result?

You are not getting the result, because the result of the callback function in con.query is not returned to the caller of getBooking. It is the asynchronous pattern, which you are not processing correctly.
The way it is supposed to work is that the getBooking gets an extra argument: a function to be called when data are available (in an internal asynchronous call to con.query). Such a function is then provided by the caller and in this function you do whatever you want with the data:
funcs.js
"getBooking": function (con, bookingId, callback) {
...
con.query(query, function(err, rows,fields) {
...
// instead of return booking do
callback(err, booking);
...
}
}
main module
// instead of
callback({"message": "Success","error":false, "booking": funcs.getBooking(con, bookingId)});
// do
funcs.getBooking(con, bookingId, function(err, booking) {
callback({"message": "Success","error":false, "booking": booking});
});
I am afraid this is not the only issue in your code, but this should be the first to fix. Read further about processing asynchronous calls in general and specifically in node.js and fix other places in your code correspondingly.

Related

get the return value of function calling from an another function node js

I have a function called uploadData in which i am calling getClientId to get the clientid. Inside the getclientId function i can get the return value. But i cant access that return value in the uploadData function. In console i am getting undefined.
uploadData(con, data, callback) {
var total = parseFloat(data.pricelist) + parseFloat(data.print)
var ac = parseFloat(total)*parseFloat(data.quantity)
var sold = parseFloat(data.soldprice)*parseFloat(data.quantity)
var rd = parseFloat(data.sold) - parseFloat(total)
var rt = parseFloat(rd) * parseFloat(data.quantity)
var client =data.client.toLowerCase()
var clientId = this.getClientId(con, data,callback)
console.log(clientId)
}
getClientId(con, data,callback) {
var client =data.client.toLowerCase()
con.query(`SELECT * from client where lower(name) = '${client}'`, function(err, rows) {
if(err) {
return err
}
else{
if(rows.length>0){
return rows[0].id
}
else{
con.query(
`INSERT INTO client SET
name = '${data.client}',
created_by = '${data.user_id}'`,
function(er, row) {
if(er){
return er
}
else{
return row.insertId
}
}
)
}
}
});
}
You can convert your function to Promise and then use async/await it will be much more readable in terms of using async call functions
getClientId(con, data,callback) {
return new Promise((resolve,reject)=>{
var client =data.client.toLowerCase()
con.query(`SELECT * from client where lower(name) = '${client}'`, function(err, rows) {
if(err) {
reject(err)
}
else{
if(rows.length>0){
resolve(rows[0].id)
}
else{
con.query(
`INSERT INTO client SET
name = '${data.client}',
created_by = '${data.user_id}'`,
function(er, row) {
if(er){
reject(er)
}
else{
resolve(row.insertId)
}
}
)
}
}
});
}
)
}
and then consume this function as
const clientId = await this.getClientId(con, data,callback);

Nodejs/Async: How does callback work in iteratee function for async.map as mentioned in code snippet

Being new to nodejs ans async following is the code that I came across.
app = express();
/*
other express use calls like - app.use(bodyParser.json());
*/
var async = require("async");
var server;
app.post('/callType/call', function(req, res) {
var startTime = Date.now();
server = req.body.server;
//async.map asynchronuously call enrollStep1 for every element in the req.body.nodes array
//HOW DOES THIS WORK??!! - WHERE IS THE CALLBACK DEFINED OR SOURCED FROM???
//******************************************************
async.map(req.body.nodes, function(node, callback) {
someFunc(node.property1,node.property2,callback)
},
//This function is called when every task triggered by async.map has called its callback.
function(err, results) {
var response = {};
if (err) {
response.success = false;
response.error = err;
console.log("ERROR returned: " + JSON.stringify(response));
res.json(response);
} else {
var returnResults = [];
//Results is an array of array - flatten it
var flattenedResults = [].concat.apply([], results);
//then remove duplicates
for (var i = 0; i < flattenedResults.length; i++){
var obj = flattenedResults[i];
var isDup = returnResults.some(function(element) {
return element.tid === obj.tid;
});
if (!isDup) {
returnResults.push(obj);
}
}
response.success = true;
response.results = returnResults;
res.json(response);
}
});
});
function someFunc(property1, property2, callback) {
var url = '/'+callTypes +'/'+ call +'/'+ property1 +'/'+ property2
urClient
.get(server + url)
.header('Content-Type', 'application/json')
.end(
function(response) {
if (response.code !== 200) {
callback("Error " + ". Code: " + response.code + " Response: " + JSON.stringify(response));
} else {
callback("Success " + ". Code: " + response.code + " Response: " + JSON.stringify(response));
}
}
);
}
The iteratee function for async.map has a definition starting function(node, callback) { but the callback function is never assigned. How does the callback work over here.
Isn't it supposed to be assigned somewhere like callback = myCallbackFunction;
The async.map takes 3 arguments, the array/object, the function to map the data and the callback function, so your code should be:
async.map(req.body.nodes, someFunc , function(err, results) {
if (err) return console.log(err);
console.log(results);
});
And your someFunc should be:
function someFunc(item, callback) {
// do something with item
// it's each item in the original array/object
callback('The results');
}
This is a basic example: http://code.runnable.com/UyR-6c2DZZ4SmfSh/async-map-example-for-node-js

Using npm async to run in parallel async methods and return a unified response

I have 2 async methods that can run independently one from each other. I would like to call a callback once both are finished. I have tried using async.parallel() (npm) but this seems to be for non async methods. How can I implement this?
Here is my async.parallel call(); note that asyncTasks is my function array, where the functions are async.
async.parallel(asyncTasks, function(resultFinal){
console.log("--------->>>>> message: "+JSON.stringify(resultFinal));
console.log("");
callback(new RequestResponse(true, resultFinal));
});
In short, what I really want is a way to execute multiple async methods in parallel and consider that method finished when the callback provided for that function is triggered.
UPDATE
for a better understanding, I've included the two functions I am using
getGroups
var getGroups = function (callback_async_1) { //get groups + members
pg.connect(datebasePath, function (err, client, done) {
var s = squel.select();
s.from("groups_members");
s.where("user_id = ?", userId);
console.log("query: " + s.toString());
client.query(s.toString(), function (err, result) { //get groups ids in which i am a member
if (err) {
console.error("error...1 " + err);
callback_async_1(responseData);
} else {
// console.log("init -- get from group_members " + JSON.stringify(result.rows));
var groupIds = [];
if (result.rows.length > 0) {
for (var i = 0; i < result.rows.length; i++) {
groupIds.push(result.rows[i].group_id); // create group ids list
}
// console.log("group ids : " + groupIds);
}
if (groupIds.length === 0) {
callback_async_1(responseData);
}
var s = squel.select();
s.from("groups");
s.where("id IN ?", groupIds);
client.query(s.toString(), function (err, result2) { // retrieve all the groups in which i take part
if (err) {
console.error("error...2 " + err);
callback_async_1(responseData);
return;
} else {
// var groupIds2 = [];
// console.log("init -- get from groups " + JSON.stringify(result2.rows));
var groups = [];
// var groups_members = [];
for (var i = 0; i < result2.rows.length; i++) {
groups.push(result2.rows[i]); // adding group info to list
// var groupId = result2.rows[i].id;
// groupIds2.push(groupId);
}
// console.log("");
//console.log(" ------->>>> " + JSON.stringify(groups));
// console.log("");
// responseData.groups = groups;
responseData.push({ //pushing groups into response
"groups": groups
});
var s = squel.select();
s.from("groups_members");
s.where("group_id IN ?", groupIds);
client.query(s.toString(), function (err, result3) { // get all the members in my groups
//console.log("get from group_members --- " + JSON.stringify(result3.rows));
var groupMembers = [];
for (var i = 0; i < result3.rows.length; i++) {
groupMembers.push({
groupMember: result3.rows[i] // pushing all the group members
});
}
//console.log("");
// console.log(" ------->>>> " + JSON.stringify(groupMembers));
// console.log("");
responseData.push({
"groupsMembers": groupMembers
});
// console.log("resulting json till now; Groups : " + JSON.stringify(responseData));
//fetching now events
var s = squel.select();
s.from("events");
s.where("group_id IN ?", groupIds);
client.query(s.toString(), function (err, result4) { //selecting all events that have my groups
if (err) {
console.error("error...3 " + err);
callback_async_1(responseData);
return;
} else {
var events = [];
for (var i = 0; i < result4.rows.length; i++) {
events.push(result4.rows[i]);
}
// responseData.events = events;
responseData.push({
"events": events
});
//responseData.push (events);
callback_async_1(responseData);
// asyncTasks[1](callback);
}
});
});
}
});
}
});
done();
});
};
getRegisteredContacts
var getRegisteredContacts = function (callback_async_2) { // get registered contacts
pg.connect(datebasePath, function (err, client, done) {
//get contacts that are registered
var s = squel.select();
s.from("users");
s.where("phone_number IN ?", arrayOfContacts);
client.query(s.toString(), function (err, result5) { // retriving registered contacts -- should be run with async parallel, it does not depend on the other calls
if (err) {
console.error(err);
callback_async_2(responseData);
} else {
if (result5.rows.length > 0) {
var contacts = [];
for (var i = 0; i < result5.rows.length; i++) {
contacts.push(result5.rows[i]);
}
responseData.push({
"registeredContacts": contacts
});
}
//console.log("");
//console.log(" ------->>>> " + JSON.stringify(events));
// console.log("");
// console.log("final ---> " + JSON.stringify(responseData));
callback_async_2(responseData);
}
});
done();
});
};
You need your task function to take a parameter which you then call when the task is done
var task = function(callback){
console.log('Task');
callback(null);
};
When you are then doing something async within the task then your task would look like
var task = function(callback){
console.log('Task');
request.get('http://www.google.com', function (error, response, body){
console.log('Task - ' + response.statusCode);
callback(null);
});
};
Example
var async = require('async');
var request = require('request');
var task1 = function(callback){
console.log('Task 1');
callback(null);
};
var task2 = function(callback){
console.log('Task 2');
request.get('http://www.google.com', function (error, response, body){
console.log('Task 2 - ' + response.statusCode);
callback(null);
});
};
var asyncTasks = [task1, task2];
async.parallel(asyncTasks, function(err, result){
console.log('--DONE--');
});
Outputs
Task 1
Task 2
Task 2 - 200
--DONE--
Based on your new code listing the most obvious thing is done() is called too early for both of your tasks. It needs to be like
var getRegisteredContacts = function (callback_async_2) {
pg.connect(datebasePath, function (err, client, done) {
var s = squel.select();
s.from("users");
s.where("phone_number IN ?", arrayOfContacts);
client.query(s.toString(), function (err, result5) {
done(); // <---- done() to be here
if (err) {
//
} else {
//
}
callback_async_2();
});
});
};
You should also lint your code. If you had you would have noticed that you had not checked if there was an err for callback pg.connect (and also keep it nicer to read correctly)

NODE.JS function callback to render page

I have a function getthem() that checks a mongo db for listings and returns name,streamurl for it.
I pass those as var stream to the renderme that renders the /dashboard page.
My problem is that i get the console.log("END OF FIND:"+JSON.stringify(stream))
to show my test input, but nothing goes to the render.
im using ejs to render. How can i get the result passed to the page ?
router.get('/dashboard', function (req, res) {
var foo = getthem();
function getthem() {
var group = "tesint";
console.log('geting for group : ' + group);
var mdlListings = require('../models/listings.js');
var myresult = "tet";
mdlListings.find({}, "name streamurl", function (err, data) {
if (err) {
console.error(err);
return;
}
if (data === null) {
console.log("No results");
return;
}
var stream = { };
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
// stream += 'name: '+streams.name+'},{streamurl: '+streams.streamurl;
// console.log("stram arry "+stream[streams.name] )
console.log("END OF FIND:"+JSON.stringify(stream))
}, renderme(stream));
// console.log("Result:", votes);
//var myresult = Object.keys(stream).map(function (name) {
// return { name: name, url: stream[name] };
//})
console.log("before return stream "+stream);
return stream;
});
}
function renderme(resa) {
console.log("RESA"+JSON.stringify(resa))
var resa = JSON.stringify(resa);
res.render('dashboard', {
title: 'Dashboard',
user: req.user,
listing: resa
}
)
}
You're passing the result of renderme(stream) as a second argument to forEach(). renderme(stream) is then evaluated immediately before your forEach() callback is called, when stream is still an empty object. My guess is you want something like this:
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
console.log("END OF FIND:"+JSON.stringify(stream))
});
renderme(stream);
Actually i figure that why would i pass the function as i could just do whatever i need to directly in there.
That worked perfectly, thanks for the tip.
data.forEach(function (streams) {
console.log("Got " + streams.name + " " + streams.streamurl);
stream[streams.name] = streams.streamurl;
});
res.render('dashboard', {
title: 'Dashboard',
user: req.user,
listing: data
}
)

Notifying caller about error from callback in node.js on error from sqlite3 call

In node.js + sqlite3:
What is a good way to notify a caller from a callback about errors and get the caller to try again ? When we get a database locked error - would like to try and run the query again.
TestController.prototype.addDevices = function (number_of_devices, callback_after_all_devices_have_been_added) {
var controller = this;
var db = controller.connectToDb();
for(i = 0; i < number_of_devices; i++) {
db.each("SELECT api_key as ak FROM user_table ORDER BY RANDOM() LIMIT 1", function(err, row) {
//sometimes we get a SQLITE: database locked error
if (err !== null) {
console.log("Error found");
//i-- this will not work - but how do we do it then?
return;
}
console.log("Error: " + err);
//code to process if we get an entry from the user_table ..
});
}
}
This is how I managed to solve this - added a retry counter and moved the problem code to its own function, passing in the epilogue as a callback. It works - but is this a good way?
(other than using promises or the async module?)
TestController.prototype.addDevices = function (number_of_devices, callback_after_all_devices_have_been_added) {
var number_of_users = 0;
var controller = this;
controller.pending_db_writes_for_device = number_of_devices;
for(i = 0; i < number_of_devices; i++) {
var api_key = controller.getRandomAPIKeyFromDB(10,function(access_key) {
var mac_address = controller.generateRandomMAC();
var friendly_name = Faker.random.array_element(["Washing Machine","Television","Dishwasher","Set top box"]);
var description = Faker.Lorem.sentence(5);
controller.registerDeviceWithAPI(mac_address, friendly_name, description, access_key, callback_after_all_devices_have_been_added);
});
}
}
TestController.prototype.getRandomAPIKeyFromDB = function (retry_counter, callback) {
var controller = this;
var db = controller.connectToDb();
console.log("Retry counter: "+ retry_counter);
db.each("SELECT api_key as ak FROM user_table ORDER BY RANDOM() LIMIT 1", function(err, row) {
if (err !== null) {
console.log("Error: " + err + "retry count: "+ retry_counter);
console.log("Error found");
if(retry_counter === 0) {
console.log("Bailing out after retry limit reached");
return;
}
controller.getRandomAPIKeyFromDB(--retry_counter,callback);
}
else {
console.log("Successfully got api key: " + row.ak);
callback(row.ak);
}
}
);
}

Resources