NodeJS Express Async issue - node.js

I have this function which gets some data from my database but i'm having a trouble calling the function and getting the proper response
function getEvents()
{
var x = [];
var l = dbCollection['e'].find({}).forEach(function(y) {
x.push(y);
});
return x;
});
and another function which calls this function but it always returns undefined.
How can i make the function wait till mongoose has finished filling up the array?
Thanks for the help! My life

dbCollection['e'].find is called non-blocking way so you are returning x before filling. You need to use callbacks or some mongoose promises. You can get all returning values from database like following snippet
function getEvents(callback) {
dbCollection['e'].find({}, function(error, results) {
// results is array.
// if you need to filter results you can do it here
return callback(error, results);
})
}
Whenever you need to call getEvents function you need to pass a callback to it.
getEvents(function(error, results) {
console.log(results); // you have results here
})
You should read mongoose docs for how queries work.
There is also support for promises in mongoose. You can check this url for more information about promises.

The solution proposed by #orhankutlu should work fine.
I will give another solution using promise. You can choose one between these two solutions depending on your style of programming.
Solution using promise:
function getEvents() {
return new Promise(function(resolve, reject){
dbCollection['e'].find({}, function(error, results) {
if (error) return reject(error);
var x = [];
results.forEach(function(y){
x.push(y);
});
// forEach() is a blocking call,
// so the promise will be resolved only
// after the forEach completes
return resolve(x);
});
});
};
Calling getEvents():
getEvents().then(function(result){
console.log(result); //should print 'x'
}).catch(function(err){
// Handle error here in case the promise is rejected
});
I will encourage you to try both the approaches, ie, using callbacks and using promises. Hope you find it useful!

Related

Program behaving abnormally due to weird async nature of nodejs

I get a post from mongodb then using that post's id I get the likes on that post, my postlikes object contains a "post" and the "likedby" array that contains usernames of people who liked it. The problem is that when i get a post, the callback for getting likes on it is somehow complex thats why node runs ahead and I couldn't get the likes i always get likes of the last post in the db mostly because the loop has reached its end then my callback is called for likes. Any solution for this??
for(var i=0;i<posts.length;i++)
{
db.collection('likes',function(err,likesCollec){
console.log("before likes posts[i].post",posts[i].post);
function wait(done){
while(done);
}
done=true;
likesCollec.find({postid:(posts[i]._id).toString()})
.toArray(function(err,likes){
console.log("posts[i].post:",posts[i].post);
postlikes[i].post=posts[i].post;
console.log("postlikes[i].post: ",postlikes[i].post);
for(j=0;j<likes.length;j++)
{
postlikes[i].likedby[j]=likes[j].username;
}
console.log(postlikes[i]);
done=false;
wait(done);
});
});
if(i==(posts.length)-1)
{
return res.json(posts);
}
}
The wait function isn't working properly also maybe I am going to the wrong direction, please help.
You may use bluebird;
var Promise = require('bluebird');
Var p = Promise.resolve();
forEach(posts, function(item, index, arr) {
p.then(new Promise(function(resolve, reject) {
// do here in sync.
resolve(); //in last
}));
});
p.then(function(){
// all tasks launched in the loop are finished.
// do extra here.
});
Use async forEach
https://www.npmjs.com/package/async
async = require('async');
async.forEach(posts,function(post, callback){
// Do functionality here
return callback();
})

Recover an object requested with MongoDB Driver on node JS

I try to recover object from a mongo DB database, in a node JS file and it doesn't work.
In a file called db.js , i have made the following code :
var MongoClient = require('mongodb').MongoClient;
module.exports = {
FindinColADSL: function() {
return MongoClient.connect("mongodb://localhost/sdb").then(function(db) {
var collection = db.collection('scollection');
return collection.find({"type" : "ADSL"}).toArray();
}).then(function(items) {
return items;
});
}
};
And, I try to use it in the file server.js :
var db = require(__dirname+'/model/db.js');
var collection = db.FindinColADSL().then(function(items) {
return items;
}, function(err) {
console.error('The promise was rejected', err, err.stack);
});
console.log(collection);
In the result I have "Promise { }". Why ?
I just want to obtain an object from the database in order to manipulate it in the others functions situated in the server.js file.
Then then function called on promises returns a promise. If a value is returned within a promise, the object the promise evaluates to is another promise which resolves to the value returned. Take a look at this question for a full explanation of how it works.
If you want to verify that your code is successfully getting the items, you will have to restructure your code to account for the structure of promises.
var db = require(__dirname+'/model/db.js');
var collection = db.FindinColADSL().then(function(items) {
console.log(items);
return items;
}, function(err) {
console.error('The promise was rejected', err, err.stack);
});
That should log your items after they are retrieved from the database.
Promises work this way to make working asynchronously more simple. If you put more code below your collection code, it would run at the same time as your database code. If you have other functions within your server.js file, you should be able to call them from within the body of your promises.
As a rule, remember a promise will always return a promise.
The callback functions created in the then() are asynchronous, thus making the console.log command execute before the promise is even resolved. Try placing it inside the callback function instead like below:
var collection = db.FindinColADSL().then(function(items) {
console.log(items)
return items;
}, function(err) {
console.error('The promise was rejected', err, err.stack);
});
Or, for the sake of another example using the logger functions themselves as the callbacks, and showing that the last console.log call will actually be called before the others.
db.findinColADSL()
.then(console.log)
.catch(console.error)
console.log('This function is triggered FIRST')

Node.js consecutive method calls with nested callback formatting

So I'm new to Node.js and Im just wondering if the way I have my code setup makes sense. Im coming from a Java background so the nested callback structure is new. I have a Node program that runs a bunch of code that I broke down into different methods. The thing is that the methods need to be called in order. My code has this structure right now:
functionOne(data, callback(err) {
functionTwo(data, callback(err) {
functionThree(data, callback(err) {
functionFour(data, callback(err) {
//Code
});
});
});
});
This is very minimalistic, but is this structure ok? With Java, I'd take the return values of all the methods, then just pass them to the next function. From my understanding so far, the Java approach I just mentioned is one of the main things that Node.js was trying to eliminate. But anyway... Does that structure look ok, and is that how its intended to look? Just want to be sure that I'm not making any major errors with Node in general. Thanks!
Your code structure looks fine if you work with callback pattern.
But if you're interested in make your code cleaner and readable you would like to use Promises in your asynchronous function, so instead of pass a callback to your functions you could do something like this :
function asyncFunction (data){
return new Promise(function(resolve, reject){
// Do something with data
// Here you can call reject(error) to throw an error
resolve();
});
}
And instead of nested function callbacks you can call then method of Promise.
asyncFunction(data)
.then(function(){
// Promise resolved
// Something has been done with data
});
With Promises you can also execute async fuctions in parallel :
Promise.all([asyncFunctionA(data), asyncFunctionB(data), asyncFunctionC(data)])
.then(function(){...});
EDIT
If you need to pass values of one function to another, your code should look like this :
asyncFunctionA(data)
.then(function(dataA){
return asyncFunctionB(dataA);
})
.then(function(dataB){
return asyncFunctionC(dataB);
})
.then(function(dataC){
// ...
});
You should try to use promises to avoid your callback hell, so it could be something like these...
const Q = require('q'); // you can do a research for this module.
var myModule = {};
myModule.functionOne = (params) => {
const deferred = Q.defer(); // wait for this to complete
// body function
deferred.resolve(data); // this would be the result of this function
return deferred.promise; // data is the output on your function
}
myModule.functionTwo = (params) => {
const deferred = Q.defer(); // wait for this to complete
// body function
deferred.resolve(data); // this would be the result of this function
return deferred.promise; // data is the output on your function
}
myModule.doAll = (params) => {
myModule.functionOne(params)
.then((outputFunctionOne) => {
// this is called after functionOne ends
return myModule.functionTwo(outputFunctionOne);
})
.then((outputFunctionTwo) => {
// this is called after function 2 ends
if (outputFunctionTwo.success) {
// if everything ok, resolve the promise with the final output
deferred.resolve(outputFunctionTwo);
} else {
// reject the promise with an error message
deferred.reject('error');
}
})
.fail((err) => {
// this is call if the promise is rejected or an exception is thrown
console.log(err); // TODO: Error handling
})
.done();
}
module.exports = myModule;
You can Chain as many promises as you want really easily, that way you get rid of the callback hell. Best part, you can do promises on Javascript or Node.js
Reference Link https://github.com/kriskowal/q
Hope this helps
Most of the other answers give Promise/A as the answer to your callback woes. This is correct, and will work for you. However I'd like to give you another option, if you are willing to drop javascript as your working language.
Introducing Iced Coffee, a branch of the CoffeeScript project.
With Iced Coffee you would write:
await functionOne data, defer err
await functionTwo data, defer err2
await functionThree data, defer err3
//etc
This then compiles to the CoffeeScript:
functionOne data, (err) ->
functionTwo data, (err2) ->
functionThree data, (err3) ->
//etc
Which then compiles to your Javascript.
functionOne(data, callback(err) {
functionTwo(data, callback(err2) {
functionThree(data, callback(err3) {
//etc
});
});
});

Nodejs mixed async functions and promises

So I have sails app with some help service to make it easier to create and get complex models.
one of theses are
getMerits: function(profileId, limit){
return async.waterfall([
function(callback){
Merit.find({employeeProfile: profileId}).then(function(merits){
callback(null, merits);
});
},
function(merits, callback){
async.forEach(merits, function(item, loop_callback){
MeritIndex.findOne({id: item.index}).then(function(meritIndex){
merits[merits.indexOf(item)].index = meritIndex;
loop_callback();
});
}, function(err, results){
callback(null, merits);
});
}
], function(err, results){
return results;
});
}
the trouble is when I try to call this function to get the result(list of merits with their meritindexes inserted.) I cant figure out the correct way to get the results returned from the async waterfall:
async.forEach(profiles, function(item, loop_callback){
MeritService.getMerits(item.id, 5).exec(function(err, merits){
console.log(merits)
profiles[profiles.indexOf(item)].merits = merits;
loop_callback();
});
// MeritService.getMerits(item.id, 5).exec(function(m){
// console.log(m)
// profiles[profiles.indexOf(item)].merits = m;
// loop_callback();
// });
}, function(err){
console.log("PROFILES" + JSON.stringify(profiles))
});
the print of merits here results in undefined. Is there any way to treat async waterfall as a promise and use then instead of exec?
You don't need to use async.waterfall since you already have promises, promises chain already - so adding another library for that logic is redundant. Waterline uses bluebird promises which come with convenience methods already.
Your getMerits can be written as:
getMerits: function(profileId, limit){
var merits = Merit.find({employeeProfile: profileId});
var items = merits.map(function(item) {
return MeritIndex.findOne({id: item.index }).then(function(meritIndex) {
item.index = meritIndex;
});
});
return items.return(merits); // wait for items to be done, and return the merits
}
P.S.
If you use Node 4+ let me know since it gets even simpler.

Loop data with Node.js

I am having my code as
function updateData(data){
data.forEach(function(obj){
users.find({_id:obj.userId}).toArray(
function(e, res) {
obj.userData = res;
console.log(res)
});
});
return data;
}
The problem is I am unable to find the updated data, I am trying to update my data and adding one more field to it based on userId. The data parameter is an array containing the output from comments table. hope you understand the scenario.
It looks that users.find({...}).toArray(function(...){...}) is going to be asynchronous, so there is no way that you can be sure that the db call has been completed and that each data.obj has been updated before data is returned.
Instead of using the javascript Array.prototype.forEach() function, you could use the NodeJS async.each function from the async library by Caolan which would iterate through the array, update each object and then return the data object only when all functions calls have completed.
For example:
var async = require("async");
function updateData(data){
async.each(data, function(obj, callback) {
users.find({_id:obj.userId}).toArray(
function(e, res) {
obj.userData = res;
callback(e);
}
);
},
function(error){
return data;
}
}

Resources