Hi i am newbie to express and promise, i am trying to call multiple asynchronous function using promise.all from express router, but it returns undefined, please guide me to solve the issue .
user.js //routes
var findAllUsersDetails = function(router){
router.post('/api/v1/users/getAllUserFormDetails',
function (req, res) {
Promise.all([
userModel.getAllUsers(req),
userModel.getAllUsers(req),
])
.then((data) => console.log(data))
.catch((err) => console.log(err))
});
}
user.js // models
var userModel = {
getAllUsers : function(req){
var string = "";
var id_company = req['user'].id_company;
var dbConnection = dbConnectionCreator();
var getAllUsers = getAllUsersSqlString(string, id_company);
console.log("ANGEL: finding all employees");
dbConnection.query(getAllUsers, function(error, results, fields){
return new Promise((resolve, reject) => {
console.log(results);
if (error) {
dbConnection.destroy();
console.log("error: ", error);
return reject (err);
} else if (results.length === 0) {
resolve("User not found.");
} else {
resolve(results);
//return (callback({employeeData: results}));
}
})
});
},
}
module.exports = userModel;
Your getAllUsers function is expected to return Promise, but is returning undefined(nothing).
The promise is returned to dbConnection.query but not to the getAllUsers function.
You can try adding return.
return dbConnection.query
if this doesn't work, then dbquery doesn't return the callback which was returned to it.
You might need to find an alternative to solve this.
Let me know if it works.
userModel.getAllUsers(req) should return Promise a.e.:
function getAllUsers(req) {
return new Promise(function(resolve, reject){
//...
});
}
In your case dbConnection.query(getAllUsers, function(error, results, fields) returns Promise therefore you can write something like:
getAllUsers : function(req){
var string = "";
var id_company = req['user'].id_company;
var dbConnection = dbConnectionCreator();
var getAllUsers = getAllUsersSqlString(string, id_company);
console.log("ANGEL: finding all employees");
return dbConnection.query(getAllUsers, function(error, results, fields){
// ^^^
return new Promise((resolve, reject) => {
console.log(results);
if (error) {
dbConnection.destroy();
console.log("error: ", error);
return reject (err);
} else if (results.length === 0) {
resolve("User not found.");
} else {
resolve(results);
}
})
});
},
What i did is i placed the dbconnection within promise function and now i can return promise with the results of dbConnection.query()
getAllUsers : function(req){
var string = "";
var id_company = req['user'].id_company;
var dbConnection = dbConnectionCreator();
var getAllUsers = getAllUsersSqlString(string, id_company);
console.log("ANGEL: finding all employees");
return new Promise((resolve, reject) => {
dbConnection.query(getAllUsers, function(error, results, fields){ //
console.log(results);
if (error) {
dbConnection.destroy();
console.log("error: ", error);
return reject (err);
} else if (results.length === 0) {
resolve("User not found.");
} else {
resolve(results);
//return (callback({employeeData: results}));
}
});
});
Thanks for your immediate reply, actually i understood issue is because of returning promise from your answers.
Related
I have written the following code in Nodejs which is saving data in MongoDB:
function insertDoc(db,data){
return new Promise(resolve => {
callback=db.collection('AnalysisCollection').insertOne(data).then(function(response,obj){
console.log("Inserted record");
resolve(obj);
//console.log(obj);
// response.on('end',function(){
// resolve(obj);
// });
//return resolve(obj);
}).then(() => { return obj }
).catch(function(error){
throw new Error(error);
});
})
}
I am calling the above function from the main function like this:
async function cosmosDBConnect(nluResultJSON){
try{
//console.log("Inserting to cosmos DB");
console.log(nluResultJSON);
var url = config.cosmos_endpoint;
var result="";
var data = JSON.parse(JSON.stringify(nluResultJSON));
MongoClient.connect(url, function(err, client) {
assert.equal(null, err);
var db = client.db('NLUAnalysisDB');
// insertDoc(db, data, function() {
result=insertDoc(db, data, function() {
console.log(result);
client.close();
//return data._id;
});
});
}
catch (e) {
console.log(e);
}
}
module.exports = { cosmosDBConnect };
But in cosmosDBConnect, I am getting 'undefined' for the result, though in insertDoc I am getting the output for'obj' with _id for the inserted record.
Please help me to return this _id to cosmosDBConnect.
You are use callbacks inside of async function, which creates internal scopes. So your return aplies to them instead of whole function. You should use Promise-based methods inside of async function using await (without callbacks) or wrap whole function into own Promise otherwise.
Example:
function cosmosDBConnect(nluResultJSON) {
return new Promise((resolve, reject) => {
var url = config.cosmos_endpoint;
var result = '';
var data = JSON.parse(JSON.stringify(nluResultJSON));
MongoClient.connect(url, function(err, client) {
if (err) return reject(err);
assert.equal(null, err);
var db = client.db('NLUAnalysisDB');
insertDoc(db, data).then(obj => {
console.log(obj);
client.close();
return resolve(data._id);
});
});
});
}
Also you need to understand that your insertDoc return Promise and do not accept callback you tried to pass.
Ref: async function
result = insertDoc(db, data).then((data) => {
console.log(data);
}).catch(err => console.error(err));
I'm new to javascript (and coding) and I'm looking into Promises.
I have the following working code:
router.get("/test", function(req, res){
var mainCategory = new Promise(function(resolve, reject){
Maincategory.find().populate("subcategory").exec(function(err, allMaincategories){
if (err) {
console.log("error 1");
reject("error 2");
}
else {
resolve(allMaincategories);
}
});
});
var itemQuery = new Promise(function(resolve, reject){
Items.find({}, function(err, allItems){
if (err) {
console.log("error 3");
reject("error 4");}
else {
resolve(allItems);
reject("error 5");
}
});
});
Promise.all([
mainCategory,
itemQuery
]).then(function(allQueries){
console.log(allQueries);
var allCategories = allQueries[0];
var allItems = allQueries[1]
var userId = "true";
var show = "list";
res.render("test.ejs", {
allCategories: allCategories,
allItems: allItems,
userId: userId,
show: show
});
}).catch(function(error){
console.log("error 6");
res.render("error.ejs", {error: error});
});
});
Question 1: Is it correct to use a callback inside a promise like that?
Question 2: Is there a (shorter) way to put all mongoose requests in one promise?
Mongoose queries return Promises already - since you're using Promises, better to just use the Promise it returns rather than to construct a new one to use with the callback:
Promise.all([
Maincategory.find().populate("subcategory").exec(),
Items.find({})
]).then(function(allQueries){
// ...
mongoose already supports promises natively, so there's no reason at all to create a promise like you are doing. This:
var mainCategory = new Promise(function(resolve, reject){
Maincategory.find().populate("subcategory").exec(function(err, allMaincategories){
if (err) {
console.log("error 1");
reject("error 2");
}
else {
resolve(allMaincategories);
}
});
});
should be replaced with
const subcatPromise = Maincategory.find().populate("subcategory").exec();
and
var itemQuery = new Promise(function(resolve, reject){
Items.find({}, function(err, allItems){
if (err) {
console.log("error 3");
reject("error 4");}
else {
resolve(allItems);
reject("error 5");
}
});
});
is equivalent to
const itemsPromise = Items.find({});
router.get("/test", async function (req, res) {
try {
const allQueries = await Promise.all([Maincategory.find().populate("subcategory").exec(), Items.find({}).exec()]),
allCategories = allQueries[0],
allItems = allQueries[1],
userId = "true",
show = "list";
res.render("test.ejs", {
allCategories: allCategories,
allItems: allItems,
userId: userId,
show: show
});
} catch (error) {
console.log("error 6");
res.render("error.ejs", {
error: error
});
};
});
exports.calculateGstBaseOnInput = function(req, res) {
console.log("welcome");
for (var item of req.body.so_items) {
req.productid = item.productid;
req.qty = item.qty;
getItemDetail(req, res).then(function(result) {
return getCartItems(req, res);
}).then(function(result) {
return calculateGST(req, res);
})
}
}
getItemDetail = function(req, res) {
return new Promise(function(resolve, reject) {
console.log("inside getItemDetail");
var SQL = "mysql query";
mysqlConnect.query(SQL, function(err, result, fields) {
if (err) {
console.log("inside err");
res.json({ status: 'Failure', statusMessage: 'item does not exist' });
} else if (result.length < 0) {
console.log("inside length 0");
res.json({ status: 'Failure', statusMessage: 'item does not exist' });
} else {
req.itemdetail = result;
console.log("price inside getitemdetail= ", req.itemdetail[0].price);
//callback();
}
});
resolve('done');
});
}
getCartItems = function(req, res) {
return new Promise(function(resolve, reject) {
console.log("inside getCartItems");
var SQL = "mysql query";
mysqlConnect.query(SQL, function(err, result, fields) {
if (err) {
res.json({ status: 'Failure', statusMessage: 'item does not exist' });
} else if (result.length < 0) {
res.json({ status: 'Failure', statusMessage: 'item does not exist' });
} else {
req.cartItems = result;
//callback();
}
});
resolve('done');
});
}
calculateGST = function(req, res) {
return new Promise(function(resolve, reject) {
console.log("inside calculateGST");
if (req.userDetails[0].is_gst_included) {
//total = req.qty * req.itemdetail[0].price;
// console.log("price = ",req.itemdetail[0].price);
//callback();
} else {
//total = req.qty * req.itemdetail[0].price;
//console.log("price = ",req.itemdetail[0].price);
//total = req.qty * req.itemdetail[0].price;
}
resolve('done');
});
}
Actual output :
inside getItemDetail
inside getItemDetail
inside getCartItems
inside getCartItems
inside calculateGST
inside calculateGST
Expected Output(output i wanted):
inside getItemDetail
inside getCartItems
inside calculateGST
inside getItemDetail
inside getCartItems
inside calculateGST
how do i achieve this without setting any time.
You are resolveing immediately instead of resolving within the callback provided to mysqlConnect.query().
Consider an abbreviated version of your getItemDetail function:
function getItemDetail(req, res) {
return new Promise(function(resolve, reject) {
var SQL = "mysql query";
mysqlConnect.query(SQL, function(err, result, fields) {
// Stuff
});
resolve('done');
});
}
It's logic is:
Create a new promise
Begin a query
resolve()
Whatever called getItemDetail does what it should because getItemDetail resolved
query finishes sometime later
Instead, you should likely be doing something like this, where resolve is within the query callback:
function getItemDetail(req, res) {
return new Promise(function(resolve, reject) {
var SQL = "mysql query";
mysqlConnect.query(SQL, function(err, result, fields) {
// Stuff
resolve('done');
});
});
}
The logic here is:
Create a new promise
Begin a query
getItemDetail caller shouldn't do anything yet because getItemDetail isn't yet resolved
query finishes at some point and the callback is triggered which calls resolve
getItemDetail caller will now proceed since it has been told that the function resolved
You need to follow this pattern in any function where you need a query to actually finish before the caller should move on.
You should also consider leveraging async/await. Consider this abbreviated example using your code as a base:
const mysqlConnect = {
query(sql, cb) {
setTimeout(() => {
cb(null, ["foo"], ["bar"]);
});
}
};
(async function() {
const t = await calculateGstBaseOnInput({
body: {
so_items: ["a", "b", "c"]
}
});
}());
async function calculateGstBaseOnInput(req, res) {
for (var item of req.body.so_items) {
const itemDetail = await getItemDetail(req, res);
const cartItems = await getCartItems(req, res);
const gst = await calculateGST(req, res);
}
}
function getItemDetail(req, res) {
console.log("getItemDetail");
return new Promise(function(resolve, reject) {
var SQL = "mysql query";
mysqlConnect.query(SQL, function(err, result, fields) {
// Stuff
resolve('done');
});
});
}
function getCartItems(req, res) {
return new Promise(function(resolve, reject) {
console.log("---getCartItems");
var SQL = "mysql query";
mysqlConnect.query(SQL, function(err, result, fields) {
// Stuff
resolve('done');
});
});
}
function calculateGST(req, res) {
return new Promise(function(resolve, reject) {
console.log("------calculateGST");
// Stuff
resolve('done');
});
}
This outputs:
getItemDetail
---getCartItems
------calculateGST
getItemDetail
---getCartItems
------calculateGST
getItemDetail
---getCartItems
------calculateGST
Hello I am new to nodejs and mongodb, i am having trouble resolving my first promise after the second promise has been resolved. I can see the result of my second promise after it is resolved. Here is my code
var getShows = function () {
return new Promise(function (resolve, reject) {
usersdb.find(function (err, result) {
if(err) return console.error(err);
var usersFromCall = result;
var task = function (users) {
return new Promise(function (resolve, reject) {
var user = {
'name': '',
'pages': []
}
user.name = users.show;
console.log(users);
pagedb.find({'show' : user.name}, function (err, resp) {
for(var j = 0 ; j <resp.length; j ++){
var pages = { 'pageId': ''};
pages.pageId = resp[j].pageId;
user.pages.push(pages);
}
console.log(user);
resolve({show: user});
})
});
};
var actions = usersFromCall.map(task);
return Promise.all(actions);
}).then(function () {
resolve()
})
});
};
do i resolve the first promise in a then function after the find?
The following should work:
var getShows = function () {
return new Promise(function (resolve, reject) {
usersdb.find(function (err, users) {
if (err) return console.error(err);
var task = function (user) {
return new Promise(/* ... */);
};
var actions = users.map(task);
Promise.all(actions).then(resolve, reject);
});
});
};
getShows().then(function (results) {
// Prints the result of each task as an array
console.log(results);
});
Looking at your code, it seems .find returns a Promise. So, just for the sake of avoiding the Promise constructor anti-pattern please try the following, I believe it will produce the correct result
var getShows = function() {
return usersdb.find()
.then(result =>
Promise.all(result.map(
users =>
pagedb.find({
show: users.show
})
.then(resp => ({
show: {
name: users.show,
pages: resp.map(item => ({pageId: item.pageId}))
}
}))
)
)
);
};
or the ES5 version
var getShows = function getShows() {
return usersdb.find().then(function (result) {
return Promise.all(result.map(function (users) {
return pagedb.find({
show: users.show
}).then(function (resp) {
return {
show: {
name: users.show,
pages: resp.map(function (item) {
return { pageId: item.pageId };
})
}
};
});
}));
});
};
It's a little complicated. Let show the code:
requestAccessToken().then(function(requestResult) { // this is the first then()
if(requestResult.ok == 1) {
return document;
}
}).then(function(document) { // this is the second then()
return db.update(updateArgu); // here, db.update will return a promise obj
}).then(function(result) { // this is the last then()
console.log('update ok');
console.log(result);
});
Since the db.update(updateArgu) will return a promise object, it can add a .then() method like db.update().then().
But I want to keep the main chain like requestAccessToken().then().then() so I returned the db.update() in the second then(). The output is:
app-0 update ok
app-0 undefined
The db.update code is:
exports.update = function(arguments) {
var name = arguments.name;
var selector = (arguments.selector) ? arguments.selector : {};
var document = (arguments.document) ? arguments.document : {};
var options = (arguments.options) ? arguments.options : {};
return Promise(resolve, reject) {
MongoClient.connect(DBURL, function(err, db) {
if(err) throw err;
db.collection(name).update(selector, document, options, function(err, result) {
db.close();
if(err) {
reject(err);
} else {
resolve(result);
}
});
});
}
}
You can see it has resolve(result), how can I transfer it to the last then()?
I'll make my comment into an answer.
Where you do:
return Promise(resolve, reject) {
...
}
it should be:
return new Promise(function(resolve, reject) {
...
});