I'm having a problem with async Node.js module. In my Node.js app, I'm trying to get an array of JSON objects returned by a MongoDB request:
var fruits = ["Peach", "Banana", "Strawberry"];
var finalTab = [];
fruits.forEach(function(fruit) {
db.collection('mycollection').distinct("column1", {"column2":{$regex :fruit}}, (function(err, result) {
finalTab[fruit] = result;
console.log(result); // -> display the desired content
db.close();
if (err) throw err;
}));
});
console.log(finalTab); // -> []
At the moment, I'm at this point.
I'm trying to implement the async.map to iterate through Fruits collection.
https://caolan.github.io/async/docs.html#map
Can someone help? :)
Thanks by advance for help.
EDIT:
As I need all results returned by my db.collection functions, I'm trying to add these async commands to a queue, execute it and get a callback function.
You can try this:
async.map(fruits , function (fruit, callback) {
db.collection('mycollection').distinct("column1", {"column2":{$regex :fruit}}, (function(err, result) {
//here you are assigning value as array property
//finalTab[fruit] = result;
// but you need to push the value in array
finalTab.push(result);
console.log(result); // -> display the desired content
db.close();
if (err) throw err;
//callback once you have result
callback();
}));
}.bind(this), function () {
console.log(finalTab); // finally call
}, function (err, result) {
return Promise.reject(err);
});
Related
Hej, have a problem. Trying to send Express response with Mongo data in it.
This is code from my Express server
var Task = require('./modules/Task');
app.get('/get-all-tasks',function(req,res){
res.setHeader('Content-Type', 'application/json');
console.log(Task.getAllTasks()); // returns undefined
res.json({msg:"Hej, this is a test"}); // returns object
});
This is mongoose model in separate file
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/todo-app');
var TaskSchema = mongoose.Schema({
name: String,
assignee: String
},{ collection : 'task' });
var Task = module.exports = mongoose.model('Task', TaskSchema);
module.exports.createTask = function (newTask, callback) {
newTask.save(callback);
}
module.exports.getAllTasks = function(){
Task.find().lean().exec(function (err, docs) {
console.log(docs); // returns json
});
}
How can I properly send data from getAllTasks function?
That's looks correct, but your are forgetting about the Javascript's asynchronous behavior :). When you code this:
module.exports.getAllTasks = function(){
Task.find().lean().exec(function (err, docs) {
console.log(docs); // returns json
});
}
You can see the json response because you are using a console.log instruction INSIDE the callback (the anonymous function that you pass to .exec())
However, when you type:
app.get('/get-all-tasks',function(req,res){
res.setHeader('Content-Type', 'application/json');
console.log(Task.getAllTasks()); //<-- You won't see any data returned
res.json({msg:"Hej, this is a test"}); // returns object
});
Console.log will execute getAllTasks() function that doesn't return anything (undefined) because the thing that really returns the data that you want is INSIDE the callback...
So, to get it work, you will need something like this:
module.exports.getAllTasks = function(callback){ // we will pass a function :)
Task.find().lean().exec(function (err, docs) {
console.log(docs); // returns json
callback(docs); // <-- call the function passed as parameter
});
}
And the we can write:
app.get('/get-all-tasks',function(req,res){
res.setHeader('Content-Type', 'application/json');
Task.getAllTasks(function(docs) {console.log(docs)}); // now this will execute, and when the Task.find().lean().exec(function (err, docs){...} ends it will call the console.log instruction
res.json({msg:"Hej, this is a test"}); // this will be executed BEFORE getAllTasks() ends ;P (because getAllTasks() is asynchronous and will take time to complete)
});
I believe what you would need to do is return the docs in your getAllTasks function, but perhaps a better way to do it asynchronously using callbacks like so:
module.exports.getAllTasks = function(callback){
Task.find().lean().exec(function (err, docs) {
// If there is an error, return the error and no results
if(err) return callback(err, null)
// No error, return the docs
callback(null, docs)
});
}
And then inside your route you would do:
app.get('/get-all-tasks',function(req,res){
Task.getAllTasks(err, docs){
if(err) return res.json(error: err)
res.json(msg: docs);
}
});
I'm not sure if getAllTasks should be a mongoose static, in which case your model would look something like this:
TaskSchema.statics.getAllTasks = function (callback) {
return this.find().lean().exec(callback);
}
I am learning Node.js; due to asynchronous of Node.js I am facing an issue:
domain.User.find({userName: new RegExp(findtext, 'i')}).sort('-created').skip(skip).limit(limit)
.exec(function(err, result) {
for(var i=0;i<result.length;i++){
console.log("result is ",result[i].id);
var camera=null;
domain.Cameras.count({"userId": result[i].id}, function (err, cameraCount) {
if(result.length-1==i){
configurationHolder.ResponseUtil.responseHandler(res, result, "User List ", false, 200);
}
})
}
})
I want to use result in Cameras callback but it is empty array here, so is there anyway to get it?
And this code is asynchronous, is it possible if we make a complete function synchronous?
#jmingov is right. You should make use of the async module to execute parallel requests to get the counts for each user returned in the User.find query.
Here's a flow for demonstration:
var Async = require('async'); //At the top of your js file.
domain.User.find({userName: new RegExp(findtext, 'i')}).sort('-created').skip(skip).limit(limit)
.exec(function(err, result) {
var cameraCountFunctions = [];
result.forEach(function(user) {
if (user && user.id)
{
console.log("result is ", user.id);
var camera=null; //What is this for?
cameraCountFunctions.push( function(callback) {
domain.Cameras.count({"userId": user.id}, function (err, cameraCount) {
if (err) return callback(err);
callback(null, cameraCount);
});
});
}
})
Async.parallel(cameraCountFunctions, function (err, cameraCounts) {
console.log(err, cameraCounts);
//CameraCounts is an array with the counts for each user.
//Evaluate and return the results here.
});
});
Try to do async programing allways when doing node.js, this is a must. Or youll end with big performance problems.
Check this module: https://github.com/caolan/async it can help.
Here is the trouble in your code:
domain.Cameras.count({
"userId": result[i].id
}, function(err, cameraCount) {
// the fn() used in the callback has 'cameraCount' as argument so
// mongoose will store the results there.
if (cameraCount.length - 1 == i) { // here is the problem
// result isnt there it should be named 'cameraCount'
configurationHolder.ResponseUtil.responseHandler(res, cameraCount, "User List ", false, 200);
}
});
I'm trying to export one function this way:
exports.query = function(request){
conn.query(request, function(err, rows, fields){
if(err) console.log(err);
return rows[0].id;
});
}
and using it:
var mysql = require('./mysql');
console.log(mysql.query('SELECT * FROM tablename'));
Proceeding this way for getting a result involves undefined as output.
How do I to fix this, please?
Note that when I just type console.log(rows[0].id) instead of return rows[0].id it sends back 123.
Thanks in advance!
In your example, the output is being returned to the anonymous function of the database query instead of the caller of the module. You can use a callback to return output to the caller of the module.
exports.query = function(request, callback){
conn.query(request, function(err, rows, fields){
if (err) {
callback(err);
} else {
callback(null, rows[0].id);
}
});
}
Then call it like
var mysql = require('./mysql');
mysql.query('SELECT * FROM tablename', function(err, results){
if (err) {
console.error(err);
} else {
console.log(results);
}
});
That's a problem of synchrony.
the conn.query function returns undefined because it finish its execution before the results are fetched (like almost any i/o related operation on js/node).
One possible solution to that, is to provide a callback to your query function.
exports.query = function(request, cb){
conn.query(request, function(err, rows, fields){
// some "special" processing
cb(err, rows, fields);
});
};
If you're not familiar with async functions, take a look on some articles about that:
http://justinklemm.com/node-js-async-tutorial/
https://www.promisejs.org/
thanks for your help...struggling big time with how to handle this properly. I'm in async now, having given up on my ability to write the callbacks properly. I have snippet where I'm passing a set of random numbers (eachrecord) and passing them through to a mongoose call. Trying to create a data set from the multiple queries I pass.
My issue is that no matter what I've done for 4 hours, the "newarray" variable is always empty.
Thank you for your help -
async.forEach(arLimit, function(eachrecord, callback){
newarray = new Array;
var query = UGC_DB_Model.find({}).skip(eachrecord).limit(-1);
query.execFind(function (err, data) {
if (err)
console.log(err);
else {
newarray.push(data);
}
});
callback(null, newarray);
}, function(err, result) {
if (err) return next(err);
console.log("(it's empty): " + result);
});
There are several issues with your code:
async.forEach isn't meant to 'generate' results, that's what async.map is for;
you need to call the callback only when execFind is done, and not immediately after calling it;
your newarray is probably not necessary;
So try this instead:
async.map(arLimit, function(eachrecord, callback){
var query = UGC_DB_Model.find({}).skip(eachrecord).limit(-1);
query.execFind(function (err, data) {
if (err)
callback(err); // pass error along
else {
callback(null, [ data ]);
// although I think you mean this (because 'data' is probably an array already)
// callback(null, data);
}
});
}, function(err, result) {
if (err) return next(err);
console.log("(it's empty): " + result);
});
ModuleTwo.js
exports.getNotificatiosById = function (notificationId) {
db.get(notificationId, function (err, doc) {
if(!err){
return true;
}
});
};
In modulelOne i need to get the result of the moduleTwo method.If moduleTwo method doesn't have the database query function means i can get that method result like below in moduleOne
var res=require('./lib/moduleTwo').getNotificatiosById;
If that db.get method has the synchronize method means i can do the query like
db.getSync(id);
Is there any other way to get the result of my moduleTwo method.Now i'm trying like below.Is it correct
moduleOne.js
var moduleTwo=require('./lib/moduleTwo');
moduleTwo.getNotificatiosById(id,function(err,res){
if(!err){
console.log('Result of the 2nd module is '+res);
}
});
You need to change getNotificatiosById to take a callback
exports.getNotificatiosById = function (notificationId,callback) {
db.get(notificationId, function (err, doc) {
if(!err){
callback(doc);
return true;
}
});
};
Then call it like
var moduleTwo=require('./lib/moduleTwo');
moduleTwo.getNotificatiosById(id,function(res){
console.log('Result of the 2nd module is '+res);
});