I can't make this promise work - node.js

I am trying to use Promises instead of Callback in my Lambda Function in NodeJs 4.3. What I'm trying to do is read a config file from S3 and use the configuration to connect to a DB and execute a SELECT statement on a table. When I test the function, I don't get any errors in the console.
I have defined my function as follows:
function setUpConnection(response) {
console.log("S3 Response " + JSON.stringify(response));
return new Promise(function(resolve, reject) {
config = response.Body.toString('utf-8');
config = JSON.parse( config );
// set up connection from S3 config file
var con = mysql.createConnection({
host: config.hostaddress,
user: config.user,
password: config.pass,
database: config.dbname
});
console.log("connection " + JSON.stringify(con));
console.log("config " + JSON.stringify(config));
// create connection
con.connect(function(err){
if(err){
// Output connection details for debugging
console.log('Error connecting to DB');
return Promise.reject(new Error(output));
}
});
// Run Select Query
con.query("SELECT * FROM goodsreceiptheader WHERE invoiceKey = ?", [invoicekey], function(err,res){
if(err){
console.log(err);
con.end();
return Promise.reject(new Error(output));
}
if ( res.length <= 0 ){
console.log('Response Object ' + JSON.stringify(res));
con.end();
return Promise.reject(new Error(output));
}
resolve(res);
})
})
}
The function is being called by this function:
// Setup goodsreceipt info
var goodsreceipt = data.goodsreceipt;
getObjectPromise = s3bucket.getObject(params).promise()
getObjectPromise
.then(setUpConnection)
.then(validateRecord)
.catch(callback(null, Error))
When I execute this code, I am only seeing the result of the code
console.log("S3 Response " + JSON.stringify(response));
on the second line. Is there a problem with the way I configured setUpConnection?

You're using rejection in a wrong way.
return Promise.reject(new Error(output));
Should be replaced with
reject(new Error(output));
return;
Also catch call looks strange: it calls callback immediately. Usually catch block looks like that:
somePromise.catch((error) => {
console.error(error); // If output required.
callback(error); // If callback provided.
});
Move con.query call inside of con.connect callback.

First of all, from where output is coming? I don't see it anywhere defined.
Second of all it is considered as good practice to always throw/reject with an instance of Error, in your example i guess, at least by variable name, output is not an instance of Error. Third thing in general only valid use case in my opinion of using new Promise constructor is when you want to transform callback api to promise which you are doing here (which is good) or you when deal with setTimeout/setInterval
Anyway you are using Promise.reject where you have reject in scope already which is not how you should reject your promise in this case. Next thing is that you are using con.query outside of callback that is provided to con.connect which effectively means you are calling query before connection was successfully established, try with something like:
return new Promise(function(resolve, reject) {
...
con.connect(function(err){
if(err){
return reject(new Error('...'));
}
// Run Select Query
con.query(..., ..., function (err,res) {
if(err){
...
return reject(new Error('...'));
}
if (res.length <= 0 ){
...
return reject(new Error(output));
}
return resolve(res);
})
});
})
Few sides notes:
1. Check does this lib have promise api, probably it should in that way you dont need to promisify things around on your own.
2. If it doesnt have you can always use libs like bluebird to promisfy code for you

You rejection of promise is wrong
Try in this way
function setUpConnection(response) {
console.log("S3 Response " + JSON.stringify(response));
return new Promise(function(resolve, reject) {
config = response.Body.toString('utf-8');
config = JSON.parse( config );
// set up connection from S3 config file
var con = mysql.createConnection({
host: config.hostaddress,
user: config.user,
password: config.pass,
database: config.dbname
});
console.log("connection " + JSON.stringify(con));
console.log("config " + JSON.stringify(config));
// create connection
con.connect(function(err){
if(err){
// Output connection details for debugging
console.log('Error connecting to DB');
return reject(err);
}
});
// Run Select Query
con.query("SELECT * FROM goodsreceiptheader WHERE invoiceKey = ?", [invoicekey], function(err,res){
if(err){
console.log(err);
con.end();
return reject(err);
}
if ( res.length <= 0 ){
console.log('Response Object ' + JSON.stringify(res));
con.end();
return reject('response less 0');
}
resolve(res);
})
})
}

Related

MongoDB not closing connections from NodeJS app

I have a node application that makes a call to mongoDB every 10 seconds, but looking at the output in my terminal, the connections just keep counting up and never seem to close:
My code to hit the ddb every 10 seconds:
const MongoClient = require("mongodb").MongoClient
setInterval(function(){
MongoClient.connect(uri, (err, client) => {
if (err){
console.log(err);
}
database = client.db(databaseName)
getData(function(data){
if(data.length > 0){
db_response = data;
params["fieldA"] = db_response[0]['fieldA'];
}
})
})
}, 10000)
function getData(callback){
var query = { fieldA: "foo" };
database.collection(CollectionName).find(query).toArray(function(err, result){
if (err){
throw err;
}
callback(result);
})
}
(The vars uri, CollectionName and databaseName are declared earlier) I guess what i need to do (and havent yet figured out) is to connect to the DB once when the server starts, and then run the getData() function on successful connection, does that mean the database variable needs to be a global var??
As you correctly identified you only need to create your db connection once. So rather than wrapping the the db connection creation with setInterval, wrap setInterval around the only function you want to repeat, in this case getData.
On your other question, the database variable doesn't need to global but you are right getData does need to use it. Therefore pass it as an argument along with your callback function.
If you want to close your connection use client.close(); inside MongoClient.connect
const MongoClient = require("mongodb").MongoClient
MongoClient.connect(uri, (err, client) => {
if (err){
console.log(err);
}
const database = client.db(databaseName);
setInterval(function(){
getData(database, function(data){
if(data.length > 0){
db_response = data;
params["fieldA"] = db_response[0]['fieldA'];
}
})
}, 10000)
})
function getData(db, callback){
var query = { fieldA: "foo" };
db.collection(CollectionName).find(query).toArray(function(err, result){
if (err){
throw err;
}
callback(result);
})
}

Variable is null after returned from lambda function in AWS

I tried to define local variable then call lambda function which populates the value to my local variable:
var listOfAliases = null;
lambda.invoke(params, function(err, data) {
if (err) {
//context.fail(err);
console.log(`This is the ERROR execution =${err} =================================`);
prompt(err);
} else {
//context.succeed('Data loaded from DB: '+ data.Payload);
listOfAliases = JSON.stringify(data.Payload);
console.log(`This is the VALIDE execution =${data.Payload} =================================`); //I can see this in the log with proper values
console.log(`This is the VALIDE execution(listOfAliases) =${listOfAliases} =================================`); //I can see this in the log with proper values
}
callback(null, JSON.parse(data.Payload));
});
console.log(`This is the DB execution listOfAliases=${listOfAliases} =================================`); //I can see this in the log with NULL value
The problem here is that lambda.invoke executes asynchronously and your last console.log executes before the invoke callback function completes.
If you need to access the result from outside one the asynchronous call completes, you could use a promise.
var promise = new Promise(function(resolve,reject){
lambda.invoke(params, function(err, data) {
if (err) {
reject(err);
} else {
resolve(JSON.stringify(data.Payload));
}
});
});
promise.then(function(listOfAliases){
console.log('This is the DB execution listOfAliases ' + listOfAliases);
});

MEAN node js promise return undefinded

I have a function that list all users and role refrenced to group. Now i have other function that take user role refid and returns group name. While trying to return name i got promise pending state.
function getAll() {
var deferred = Q.defer();
db.users.find().toArray(function(err, users) {
if (err) deferred.reject(err.name + ': ' + err.message);
// return users (without hashed passwords)
users = _.map(users, function(user) {
//console.log(user);
return _.omit(user, ['hash']);
});
users = _.map(users, function(user){
refId = {}= user['role'][0]['oid']['_id'];
//console.log(typeof refId);
user = _.omit(user, ['role']);
user.role = userRole.userRole(refId).then(function(err,rid){
if(err){
deferred.reject(err.name+':'+err.message);
}
deferred.resolve();
console.log(deferred.resolve(rid));
return deferred.promise;
console.log(deferred.promise);
});
return user;
//console.log(user);
})
// getRefId(users)
//console.log(users);
deferred.resolve(users);
});
function userRole(rid){
return new Promise((resolve, reject) => {
db.groups.findOne({"_id":rid}, function(err, doc){
if(err){
reject(err.name + ':' + err.message);
}
if(doc){
resolve({"name": doc.name});
//console.log(doc.name);
}
})
})
}
You you want to use Promises with Mongoose or the native Mongo driver for Node which you seem to be doing here, you don't have to use new Promise() everywhere. You can use the promises directly.
See the docs:
The official MongoDB Node.js driver provides both callback based as well as Promised based interaction with MongoDB allowing applications to take full advantage of the new features in ES6.
https://mongodb.github.io/node-mongodb-native/
Mongoose async operations, like .save() and queries, return Promises/A+ conformant promises. This means that you can do things like MyModel.findOne({}).then() and yield MyModel.findOne({}).exec() (if you're using co).
http://mongoosejs.com/docs/promises.html
Instead of this:
function userRole(rid){
return new Promise((resolve, reject) => {
db.groups.findOne({"_id":rid}, function(err, doc){
if(err){
reject(err.name + ':' + err.message);
}
if(doc){
resolve({"name": doc.name});
//console.log(doc.name);
}
})
})
}
you should be able to use:
function userRole(rid){
return db.groups.findOne({ _id: rid });
}
or:
const userRole = rid => db.groups.findOne({ _id: rid });
Now, in your version there is one problem - the promise will never get resolved if there is no error but the returned doc is falsy, which can happen. But there is no point in creating your own promises if the methods that you call return promises in the first place.
Even if you want custom error messages, you can still use:
function userRole(rid){
return db.groups.findOne({ _id: rid })
.catch(function (err) {
return Promise.reject(err.name + ':' + err.message);
});
}
or this with more modern syntax:
const userRole = rid => db.groups.findOne({ _id: rid })
.catch(err => Promise.reject(`${err.name}:${err.message}`));

Node / Express & Postgresql - when no rows match

Hello I am new to Postgresql and I wanted to learn how one handles 0 results as an error is thrown. Essentially I want to get a user if it doesn't exist, return null if one doesn't, and have an error handler. Below is the current code I am using. Any tips on a better way to do this are appreciated!
var options = {
// Initialization Options
promiseLib: promise
};
var pgp = require('pg-promise')(options);
var connectionString = 'postgres://localhost:5432/myDbName';
var db = pgp(connectionString);
function getUser(id) {
let user = new Promise(function(resolve, reject) {
try {
db.one('select * from users where loginName = $1', id).then(function(data) {
console.log(data);
resolve(data);
}).catch (function (e) {
console.log('error: '+e);
reject(e);
});
}
catch (e) {
console.log('error: '+e);
reject(e);
}
});
return user;
}
output in console:
error: QueryResultError {
code: queryResultErrorCode.noData
message: "No data returned from the query."
received: 0
query: "select * from users where loginName = 'someUserName'"
}
I am the author of pg-promise.
In the realm of promises one uses .then to handle all normal situations and .catch to handle all error situations.
Translated into pg-promise, which adheres to that rule, you execute a database method that resolves with results that represent all the normal situations, so anything else ends up in .catch.
Case in point, if returning one or no rows is a normal situation for your query, you should be using method oneOrNone. It is only when returning no row is an invalid situation you would use method one.
As per the API, method oneOrNone resolves with the data row found, or with null when no row found, which you can check then:
db.oneOrNone('select * from users where loginName = $1', id)
.then(user=> {
if (user) {
// user found
} else {
// user not found
}
})
.catch(error=> {
// something went wrong;
});
If, however, you have a query for which returning no data does represent an error, the proper way of checking for returning no rows would be like this:
var QRE = pgp.errors.QueryResultError;
var qrec = pgp.errors.queryResultErrorCode;
db.one('select * from users where loginName = $1', id)
.then(user=> {
// normal situation;
})
.catch(error=> {
if (error instanceof QRE && error.code === qrec.noData) {
// found no row
} else {
// something else is wrong;
}
});
Similar considerations are made when choosing method many vs manyOrNone (method any is a shorter alias for manyOrNone).
Type QueryResultError has a very friendly console output, just like all other types in the library, to give you a good idea of how to handle the situation.
In your catch handler for the query, just test for that error. Looking at pg-promise source code, a code of noData is 0. So just do something like this:
db.one('select * from users where loginName = $1', id).then(function(data) {
console.log(data);
resolve(data);
}).catch (function (e) {
if(e.code === 0){
resolve(null);
}
console.log('error: '+e);
reject(e);
});

NodeJs promises returning too early

I'm new to NodeJs and code I'm working with is using Q framework for promises.
And it seems that I don't understand the 'Q' framework too well, I'm running into a case when promises are returning too early.
Here is my code:
BridgeInfo.getBridgeInfo(exten)
.then(function processBridgeInfo(bridge_info) {
console.log("Nitesh -- bridge info is back, yay");
if (bridge_info !== undefined) {
conf_bridge = new VoxConfBridge(ari);
conf_bridge.init(bridge_info);
/**Add the bridge to the bridgeList**/
bridgeList[conf_bridge.bridge.id] = conf_bridge;
console.log("Bridge ID to register is "+ conf_bridge.bridge.id);
self.registerEvents(conf_bridge.bridge);
conf_bridge.registerUser(event, false, channel);
} else {
console.log("Unknown extension [" + exten + "] blocking it");
ChannelDriver.blockChannel(ari, channel.id);
}
})
.catch(function handleError(err) {
console.error("Nitesh -- [voxbridgemanager] error occured "+err);
});
The above code calls a function getBridgeInfo, this function is supposed to do some DB queries and return the result.
Here is the code in getBridgeInfo
BridgeInfo.getBridgeInfo = Q.async(function(bridge_identifier) {
console.log("Nitesh -- Getting the bridge info for ["+ bridge_identifier + "]");
if (bridge_identifier !== undefined) {
db.getConfBridgeProfile(bridge_identifier)
.then(function processBridgeProfile(result) {
if (result !== undefined) {
console.log("Nitesh -- Bridge Info is "+ JSON.stringify(result));
var bridge_info = new BridgeInfo();
bridge_info.init(result)
.then (function bridgeInfoInitDone() {
return bridge_info;
})
.catch( function handleError(err) {
console.error("Nitesh ---[bridgeInfoInit] Error is "+ err);
});
}
else {
console.log("Can't find any bridge profile for this identifier ["+ bridge_identifier + "]");
}
}, function handleError(err) {
console.error("Failed to retrieve bridgeInfo");
});
} else {
console.error("Received an invalid identifier");
}
});
**When I run this code, I see that in my main code,which calls getBrigeInfo, it hits its catch error handler even before getBRidgeInfo has executed completely, getBridgeInfo's SQL query results appear afterwards.
I think the way I'm using promises isn't being done correctly, any explanations please
Your missing the key part of what promises can do.
You should not need to do any catch statements in your getBridgeInfo. You should return the whole promise that gets the SQL data... and handle it in your first block of code BridgeInfo.getBridgeInfo(exten)
Assuming that db.getConfBridgeProfile(bridge_identifier); returns a promise
Example:
BridgeInfo.getBridgeInfo = function(bridge_identifier) {
console.log("Nitesh -- Getting the bridge info for ["+ bridge_identifier + "]");
if (bridge_identifier !== undefined) {
return Q.fcall(function () {
throw new Error("Received an invalid identifier");
});
}
return db.getConfBridgeProfile(bridge_identifier);
}
I've also seperated out your process query... keep things simple.
BridgeInfo.processBridgeProfile = function(result) {
if (result !== undefined) {
console.log("Nitesh -- Bridge Info is "+ JSON.stringify(result));
var bridge_info = new BridgeInfo();
return bridge_info.init(result);
}else{
return Q.fcall(function () {
throw new Error("Can't find any bridge profile for this identifier ["+ bridge_identifier + "]");
});
}
Return promises and handle the catch in the main function. Your getting stuck in handling a catch, the SQL results are not getting returned like they should.
Call:
BridgeInfo.getBridgeInfo(bridge_identifier).then(function(result){
return BridgeInfo.processBridgeProfile(result)
}).then(function(){
//Do the rest here
}).catch(function(){
//One catch to rule them all :)
});

Resources