I am new to Node.js and mongoose, i am trying to query objects from a mongo collection using find({}) and the function is as follows :
schema.statics.listAllQuizes = function listAllQuizes(){
Model.find({},function(err,quizes,cb){
if(err){
return cb(err);
}else if(!quizes){
return cb();
}
else {
return cb(err,quizes);
}
});};
But when i call this function i get an error saying
return cb(err,quizes);
^
TypeError: cb is not a function
I am stuck at this point, can someone please help me with this, thanks in advance.
The callback should an argument to listAllQuizes, not an argument to the anonymous handler function.
In other words:
schema.statics.listAllQuizes = function listAllQuizes(cb) {
Model.find({}, function(err, quizes) {
if (err) {
return cb(err);
} else if (! quizes) {
return cb();
} else {
return cb(err, quizes);
}
});
};
Which, logically, is almost the same as this:
schema.statics.listAllQuizes = function listAllQuizes(cb) {
Model.find({}, cb);
};
Here's an example on how to use it:
var quiz = App.model('quiz');
function home(req, res) {
quiz.listAllQuizes(function(err, quizes) {
if (err) return res.sendStatus(500);
for (var i = 0; i < quizes.length; i++) {
console.log(quizes[i].quizName)
}
res.render('quiz', { quizList : quizes });
});
}
Assuming you have code somewhere that looks like this:
foo.listAllQuizzes(function (err, quizzes) {
...
});
Then your function listAllQuizzes is passed a callback:
schema.statics.listAllQuizzes = function (cb) {
Model.find({}, function(err, quizzes) {
if (err) return cb(err);
cb(null, quizzes);
});
};
Related
I have an async waterfall Array where the function otherIngrLists() is the 3rd to be executed. Every function before that worked fine.
function otherIngrLists(userslist, callback){
collection = db.get('ingrList');
collection.find({"userid":{$ne:userid}},{},function(err,docs){
if(!err){
var otherLists = docs;
var otherListsCount = docs.count();
console.log(otherListsCount);
callback(null, otherLists, otherListsCount, userslist);
} else {
callback(err, null);
}
});
},
The Problem is that this function is called twice. I assured this with a simple console.log().
How did I manage to call this function again? Did I get the concept of callbacks wrong as I use them to be passed on to the next function?
Also after this function executing twice an error ist thrown. It has nothing to to with this problem though and I will concern my self with that later.
Thank you for your time!
Waterfall Array in router.get:
router.get('/:userid', function(req, res) {
var db = req.db;
var collection;
var userid = req.params.userid;
async.waterfall(
[
function getIngrList(callback, userid) {
var route = 'http://localhost:3000/users/zutatenliste/'+userid;
request(route, function(err, response, body){
if (!err && response.statusCode === 200) {
var userlist = body;
callback(null, userlist);
} else {
callback(err, null);
return;
}
});
},
function otherIngrLists(userlist, callback){
collection = db.get('zutatenListe');
console.log(userid);
collection.find({"userid":{$ne:userid}},{},function(err,docs){
if(!err){
var otherLists = docs;
var otherListsCount = docs.count();
callback(null, otherLists, otherListsCount, userlist);
} else {
callback(err, null);
}
});
},
function pushInArray(otherLists, otherListsCount, userlist, callback){
console.log("test");
...
...}
}
}
Edit 1: --Also either if cases are executed, first the true one then the false--
// Does not happen anymore
Edit 2: Added the whole Thing until the problematic function
Please provide some Additional details as this function seems perfect and No, You haven't misunderstood the concept of callback you are using it correctly.
Structure of Async Waterfall
var create = function (req, res) {
async.waterfall([
_function1(req),
_function2,
_function3
], function (error, success) {
if (error) { alert('Something is wrong!'); }
return alert('Done!');
});
};
function _function1 (req) {
return function (callback) {
var something = req.body;
callback (null, something);
}
}
function _function2 (something, callback) {
return function (callback) {
var somethingelse = function () { // do something here };
callback (err, somethingelse);
}
}
function _function3 (something, callback) {
return function (callback) {
var somethingmore = function () { // do something here };
callback (err, somethingmore);
}
}
so, in waterfall you can pass the values to the next function and your 3rd function is correct.
Edited
async.waterfall(
[
//can not give userId as second parameter
function getIngrList(callback) {
//if you want userId you can pass as I shown above or directly use here if it's accessible
var route = 'http://localhost:3000/users/zutatenliste/'+userid;
request(route, function(err, response, body){
if (!err && response.statusCode === 200) {
var userlist = body;
callback(null, userlist);
} else {
callback(err, null);
// return; no need
}
});
},
function otherIngrLists(userlist, callback){
collection = db.get('zutatenListe');
console.log(userid);
collection.find({"userid":{$ne:userid}},{},function(err,docs){
if(!err){
var otherLists = docs;
var otherListsCount = docs.count();
callback(null, otherLists, otherListsCount, userlist);
} else {
callback(err, null);
}
});
},
function pushInArray(otherLists, otherListsCount, userlist, callback){
console.log("test");
...
...}
As said you can not pass userId as last parameter over there. Let me know if you still get the same error.
First you need to declare you function:
function myFuntion(userId, callback) {
async.waterfall([
function(callback) {
//do some thing here
callback(null, userlist);
}, function(userId, callback) {
//do something here
callback(null, orderList, orderListCount, userlist);
}
], function(err, orderList, orderListCount, userlist) {
if(err)
console.log(err);
else
callback(orderList, orderList, userlist);
})
}
After that you can use function:
myFuntion(userId, function(orderList, orderListCount, userlist) {
console.log(orderList);
console.log(orderListCount);
console.log(userlist);
})
function(dataValue, cb) {
req.app.db.models.User.find({
_id: { $ne: dataValue._id }
}, function(err, totalUser) {
if (!err) {
var len = totalUser.length;
if (len !== 0) {
req.app.utility.async.map(totalUser, function(each, callback) {
console.log(each);
req.app.utility.async.mapSeries(each.nonregisterContact, function(element, callback1) {
console.log('element', element.number);
console.log('dataValue', dataValue.mobileNumber);
console.log('kolka', Number(element.number) === Number(dataValue.mobileNumber));
if (Number(element.number) === Number(dataValue.mobileNumber)) {
each.registerContact.push(dataValue._id.toString());
each.nonregisterContact.splice(element, 1);
each.save(function(err, finalResult) {
if (!err) {
} else {
console.log(err);
}
})
callback1(null, null);
} else {
callback1(null, null);
}
}, function(err, final) {
if (!err) {
callback(null, null);
} else {
console.log(err);
}
});
}, function(err, result) {
if (!err) {
console.log('2');
return cb(null, dataValue);
} else {
console.log(err);
}
});
} else {
return cb(null, dataValue);
}
} else {
cb(err);
}
})
}
I don't get any response after each.save method call in the mapSeries method final callback.I am trying this solution.How i will do the same thing. How I resolve that and handle this kind of situation?
I tried to simplify code, but I'm not sure that my code realizes your needs. Also I cann't test it :D
dataValue, each, element, finalResult are very common names, so you should use them with caution to keep code is readable/supportable.
// very bad idea is include other libraries to app
var async = require('async');
var db = require('db'); // this module must export connection to db
...
function (dataValue, cb) {
// processUser use data from closure of current function => inside of current
function processUser (user, callback) {
async.mapSeries(user.nonregisterContact, function(contact, callback){
// Check and exit if condition is not satisfied. It's more readable.
if (Number(contact.number) !== Number(dataValue.mobileNumber))
return callback(null); // ignore user
user.registerContact.push(dataValue._id.toString());
user.nonregisterContact.splice(contact, 1);
user.save(function(err, finalResult) { // Is finalResult ignore?
if (err)
console.log(err);
callback(); // ingnore error
})
}, callback);
db.models.User.find({_id: { $ne: dataValue._id }}, function(err, userList) {
if (!err)
return cb(err);
if (userList.length == 0)
return cb(new Error('Users not found'));
// use named function to avoid stairs of {}
async.map(userList, processUser, cb);
})
};
How can I return a object of data returned by asynchronous function called multiple times from within a asynchronous function.
I'm trying to implement like this :
var figlet = require('figlet');
function art(dataToArt, callback)
{
var arry[];
figlet(dataToArt, function(err, data) {
if (err) {
console.log('Something went wrong...');
console.dir(err);
return callback('');
}
arry[0] = data;
callback(arry);
});
figlet(dataToArt, function(err, data) {
if (err) {
console.log('Something went wrong...');
console.dir(err);
return callback('');
}
arry[1] = data;
callback(arry);
});
}
art('Hello World', function (data){
console.log(data);
});
How can I do it correctly, I searched and searched but couldn't find a solution.
Ps. I'm using Figlet.js
I don't know if you're ok using an external module, but you can use tiptoe.
Install it using npm install tiptoe like any regular module and it basically goes like this:
var tiptoe = require('tiptoe')
function someAsyncFunction(obj, callback) {
// something something
callback(null, processedData);
}
tiptoe(
function() {
var self = this;
var arr = ['there', 'are', 'some', 'items', 'here'];
arr.forEach(function(item) {
someAsyncFunction(item, self.parallel());
});
},
function() {
var data = Array.prototype.slice.call(arguments);
doSomethingWithData(data, this);
},
function(err) {
if (err) throw (err);
console.log('all done.');
}
);
the someAsyncFunction() is the async function you want to call does something and calls the callback parameter as a function with the parameters error and data. The data parameter will get passed as an array item to the following function on the tiptoe flow.
Did it Myself :) Thanks to mostafa-samir's post
var figlet = require('figlet');
function WaterfallOver(list, iterator, callback) {
var nextItemIndex = 1;
function report() {
nextItemIndex++;
if(nextItemIndex === list.length)
callback();
else
iterator([list[0],list[nextItemIndex]], report);
}
iterator([list[0],list[1]], report);
}
var FinalResult = [];
WaterfallOver(["hello","Standard","Ghost"], function(path, report) {
figlet.text(path[0], { font: path[1] }, function(err, data) {
if (err) {
FinalResult.push("Font name error try help");
report();
return;
}
data = '<pre>.\n' + data + '</pre>';
FinalResult.push(data);
report();
});
}, function() {
console.log(FinalResult[0]);
console.log(FinalResult[1]);
});
I use the following code and it seems that the callback (Which start with Im HERE) is not called, any idea why?
console.log("im starting");
process.start(function() {
//this line doesnt called
console.log("im HERE");
server.listen(app.get('port'), function(err) {
if (err) {
console.error(err);
} else {
console.log(' listen to: ' + app.get('port'));
}
});
});
the method start are called and finish ...any idea what it can be ?
before ive added the process.start the code look like following:
And this works OK, now I need to add this process.start and when it finish to do the server.listen
module.exports = (function() {
server.listen(app.get('port'), function(err) {
if (err) {
console.error(err);
} else {
console.log('listen ' + app.get('port'));
}
});
}());
UPDATE
This is the code of process start
exports.start = function () {
Validator.validateJson(function (err) {
console.log(err);
process.exit(1);
});
plugin.parse().then(function (conf) {
require.cache.pe.configObj = conf;
}, function (err) {
console.log(err);
});
envHandler.eventE.on('AppP', function () {
console.log('User port ' + require.cache.per);
});
var run= function () {
return Promise.all([
childPro.create(path.join(value)),
childPro.findAndUpdateUser()
]).spread(function (cmd,updatedAppEnv) {
return Promise.all([childProc.executeChildProcess('exec', cmd, updatedAppEnv), Promise.delay(50).then(function (results) {
return inter.ProcessRun(val);
})]);
})
}();
}
I use promise lib like bluebird if its matter in this case
It's a bit unclear where you want to call the callback. In short, change the start function to accept a callback parameter and call callback() when you are done (or pass it at end as argument to then).
exports.start = function (callback) {
Validator.validateJson(function (err) {
console.log(err);
process.exit(1);
});
plugin.parse().then(function (configObj) {
if (typeof require.cache.persist === 'undefined') {
require.cache.persist = {};
}
require.cache.persist.configObj = configObj;
}, function (err) {
console.log(err);
});
envHandler.eventEmitterIns.on('AppPortDef', function () {
console.log('User port ' + require.cache.persist.port);
});
var run= function () {
return Promise.all([
childPro.create(path.join(value)),
childPro.findAndUpdateUser()
]).spread(function (cmd,updatedAppEnv) {
return Promise.all([childProc.executeChildProcess('exec', cmd, updatedAppEnv), Promise.delay(50).then(function (results) {
return inter.ProcessRun(val);
})]);
})
}();
run.then(callback);
}
(First: I'm sorry, I don't speak english very well!)
I wanna return the results of 3 finds in one array.
My code (next) is running well, but I'm in callback hell!
_Schema
.static('retrieveAll', function(cb) {
query = {};
this.find(query, function(err, data) {
if(err) {
cb(err, null);
return;
}
if(data)
all = data;
else
all = [];
_StoresModel.find(query).select('contact address').exec(function(err, data) {
if(err) {
cb(err, null);
return;
}
if(data) {
all = data.reduce(function(coll, item) {
coll.push(item);
return coll;
}, all);
}
_CustomersModel.find(query).select('contact address').exec(function(err, data) {
if(err) {
cb(err, null);
return;
}
if(data) {
all = data.reduce(function(coll, item) {
coll.push(item);
return coll;
}, all);
}
cb(null, all);
});
});
});
});
I've a FIND inside a FIND inside a FIND.
Is there anyway to improve this?
SOLUTION:
_Schema
.static('retrieveAll', function(cb) {
var model = this;
_async.parallel(
{ contacts: function(cb) {
model.find({}).exec(cb);
}
, stores: function(cb) {
_StoresModel.find({}).select('contact address').exec(cb);
}
, costumers: function(cb) {
_CostumersModel.find({}).select('contact address').exec(cb);
}
}
, function(err, data) {
if(err) {
cb(err, null);
return
}
var ret = [];
if(data.contacts.length > 0) {
ret = ret.concat(data.contacts);
}
if(data.stores.length > 0) {
ret = ret.concat(data.stores);
}
if(data.costumers.length > 0) {
ret = ret.concat(data.costumers);
}
cb(null, ret);
});
You can try using Promises.
(untested) example:
var RSVP = require('rsvp');
var all = [];
_Schema.static('retrieveAll', function(cb) {
query = {};
findPromise(this, query)
.then(function (data) {
all = data;
return findPromise(_StoresModel, query, 'contact address');
})
.then(function (stores) {
all = all.concat(stores);
return findPromise(_CustomersModel, query, 'contact address');
})
.then(function (customers) {
all = all.concat(customers);
cb(null, all);
})
.catch(function (err) {
cb(err, null);
});
});
function findPromise(Model, query, select) {
return new RSVP.Promise(function (resolve, reject) {
Model.find(query).select(select || '*').exec(function (err, data) {
return err ? reject(err) : resolve(data);
});
});
}
That example is using RSVP, but there are also other promise implementations such as Q and bluebird.
And a side note, you can use concat to concatenate arrays instead of using reduce.
take a look at npm Async. It a great library of different patterns that can be used on node.js.
You will probably want to use the waterfall if there is a Chronological priority or parallel pattern if they can all execute in parallel.
Some server-side promise libraries like q and bluebird would clean up your code substantially and eliminate the mess of callback hell.