Callback is not a function error [Nodejs] - node.js

I have the following code
var getUrl = function(callback) {
ref.once('value')
.then(function(snap) {
let article_url = snap.val();
console.log(article_url);
callback(null, article_url); // I dont want to throw an error, so I pass null for the error argument
});
};
var getImage = function(err, data, callback) {
//if (err) throw err; // Check for the error and throw if it exists.
textapi.extract({
url: data,
best_image: true
}, function(error, response) {
if (error === null) {
//console.log(response.image);
if (response.image == null || response.image == "") {
image = "https://www.wefornews.com/wp-content/uploads/2017/01/news-3.jpg"
} else {
image = response.image;
}
}
});
callback(null, image); // Otherwise proceed as usual.
};
var updateDatabase = function(err, data) {
//if (err) throw err; // Check for the error and throw if it exists.
refupdate.update ({
"Article_Image_URL": data
});
console.log('success'); // Otherwise proceed as usual
};
getUrl(getImage);
getImage(updateDatabase);
However I get an error callback is not a function at the line callback(null, image);
The thing is if I remove the updateDatabase function then I get no errors. However when it is within the code I get the error mentioned above.
Can someone please tell me what can be causing this error?

When you call getUrl(getImage), the getImage function is passed as the callback parameter to getUrl. getUrl then calls this callback parameter, passing two parameters.
callback(null, article_url)
but getImage expects three parameters
var getImage = function(err, data, callback)
so callback inside the getImage function is undefined, and when you try to call undefined as a function
callback(null, image)
... you get your callback is not a function error.
Solution
You need to nest your callbacks so the functions are called in the correct order, with the correct parameters.
getUrl(function (err, article_url) {
getImage(err, article_url, function (err, image) {
updateDatabase(err, image);
});
});
This could also be simplified since you want to call updateDatabase directly after getImage completes.
getUrl(function (err, article_url) {
getImage(err, article_url, updateDatabase);
});
Also, in your getImage function, the callback is called before your textapi.extract function completes, which is probably not want you want.
Before
var getImage = function(err, data, callback) {
textapi.extract({
url: data,
best_image: true
}, function(error, response) {
/* code */
});
callback(null, image); // This will get called immediately, without waiting for textapi.extract
};
After
var getImage = function(err, data, callback) {
textapi.extract({
url: data,
best_image: true
}, function(error, response) {
/* code */
callback(null, image); // Callback moved here, so it gets called after textapi.extract completes
});
};

const updateDatabase = async (value) => {
try {
let snap = await ref.once(value);
let article_url = snap.val();
let image = await textapi.extract({
url: article_url,
best_image: true
});
if (image==='') {image = 'https://www.wefornews.com/wp-content/uploads/2017/01/news-3.jpg'}
refupdate.update({
"Article_Image_URL": article_url
});
} catch (err) {
throw err;
}
}

because you don't provide any callback on this call getImage(updateDatabase); (last line) ?

Related

Mongoose eachAsync: execution order of promises unexpected

I am using the libraries mongoose 5.4.20, request 2.88.0, q 1.5.1, and deasync 0.1.14.
When using .cursor() and .eachAsync() the promises don't get resolved in the order I would expect. In particular, I make a request to the data base, and for each returned document, I make several external requests via an async series. The sample code is as follows:
Request Promise:
function Request (options) {
const result = Q.defer();
request(options, function (error, response, body) {
if (error) {
result.reject(error);
} else {
result.resolve(body);
}
});
return result.promise;
}
Async Series Promise:
function Series (entry) {
const result = Q.defer();
const errors = [];
//Iterate over some given array
async.eachSeries(array, function (doc, cb) {
//Make some async request
return Request(doc)
.then(function (body) {
//do stuff with 'body' and 'entry'
})
.then(function () {
//Move to the next doc in 'array'
return cb(null);
})
.fail(function (err) {
//Handle errors
errors.push(err);
//Move to the next doc in 'array'
return cb(null);
});
}, function (err, results) {
if (err) {
errors.push(err);
}
if (errors.length !== 0) {
result.reject(errors);
} else {
console.log('A');
result.resolve();
}
});
return result.promise;
}
Mongoose:
mongooseModel
.find()
.cursor()
.eachAsync(entry => Series(entry))
.then(function () {
console.log('B');
}, function (err) {
console.log(err);
});
What confuses me is that the final callback in .then() after .eachAsync() seems to be called before the promise in .eachAsync() is resolved, i.e. 'console.log('B')' is called before 'console.log('A')'. I would have expected, that .eachAsync() will wait until the promise is resolved, then pulls the next document from the collection and so on, and only at the very end, when all promises are resolved, the final .then() is called.
Any suggestion as to what I am doing wrong would be greatly appreciated. Thanks.

NodeJS Async - Continue execution for multiple http requests even if some fail

I am trying to make multiple HTTP requests and cumulate, display the results in NodeJS using the following code:
const async = require('async');
const request = require('request');
function httpGet(url, callback) {
const options = {
url : url,
json : true
};
request(options,
function(err, res, body) {
console.log("invoked")
callback(err, body);
}
).on('error', function(err) {
console.log(err)
});
}
const urls= [
"http://1.2.3.4:30500/status/health/summary",
"http://5.6.7.8:30505/status/health/summary"
];
async.map(urls, httpGet, function (err, res){
if (err)
console.log(err);
else
console.log(res);
});
The problem here is, if the first request(http://1.2.3.4:30500/status/health/summary) fails (like connection refused etc.), the second one does not go through. I know that I am making a silly mistake but cannot find it. Any help appreciated !
In async.map if one of the calls passes an error to its callback, the main callback (for the map function) is immediately called with the error(this is the problem in your case). In order not to terminate on the first error, don't call the callback with err param in your httpGet.
Use async each, it receives a list of arguments and a function, and calls the function with each element, make sure in your httpGet inside on error you call the callback, without the err, this will make rest of the calls to continue even if there was an error in some of the calls. This can work for map too but, I think the more suitable function for your case is async.each, instead of map, also you can limit the number of concurrent calls with eachLimit method.
Check https://caolan.github.io/async/docs.html#each
const async = require('async');
const request = require('request');
function httpGet(url, callback) {
const options = {
url : url,
json : true
};
request(options,
function(err, res, body) {
if (err){
console.log(err);
callback();
return;
}
console.log("invoked")
callback(null, body);
}
).on('error', function(err) {
console.log(err);
callback();
});
}
const urls= [
"http://1.2.3.4:30500/status/health/summary",
"http://5.6.7.8:30505/status/health/summary"
];
async.each(urls, httpGet, function (err, res) {
}, function (err, res) {
});
If you want async.map NOT to fail fast you could do it like this
const async = require('async');
const request = require('request');
function httpGet(url, callback) {
const options = {
url : url,
json : true
};
request(options,
function alwaysReportSuccess(err, res, body) {
callback(null, {
success: !err,
result: err ? err : body
});
}
).on('error', function(err) {
console.log(err)
});
}
const urls= [
"http://1.2.3.4:30500/status/health/summary",
"http://5.6.7.8:30505/status/health/summary"
];
async.map(urls, httpGet, function alwaysOk(_, res){
console.log(res); // will be an array with success flags and results
});

unable to return data from module in express node js

I have written below code in one file:
models/exported.js
module.exports = {
processedList: function(store_name) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) return console.error(err);
return value;
}).select('tid -_id');
}, // Export connection here
};
I have another file in routes
routes/exported.js
var exported = require('../models/exported.js');
var tradeIds = exported.processedList(storename);
console.log('simer'+tradeIds);
}
but I get undefined in console.log. If instead of return statement in processedlist I write console.log then the result gets console. But my requirement is to return data from model file to route file.
I am new to express and node js.
I guidance would be highly appreciated.
Acoording to your question, you want calling a function from route and get return response from your function to route. simple use callback functions.
models/exported.js
module.exports = {
processedList: function (store_name, callback) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) {
callback("error", err)
} else {
callback("success", value)
}
}).select('tid -_id');
}
}
routes/exported.js
var exported = require('../models/exported.js');
exported.processedList('storename', function (err, results) {
if (err == 'error') {
console.log(err);
} else {
console.log(results);
}
});
You are trying sync operation in async environment. processedList may or may not have completed when you try to console log tradeIds. NodeJS would not wait for it to complete because it is asynchronous in nature (by design and it is not a bug). You can pass callback rather than executing this way.
models/exported.js
module.exports = {
processedList: function(store_name, cb) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) return cb(err);
cb(null, value);
}).select('tid -_id');
}, // Export connection here
};
routes/exported.js
var exported = require('../models/exported.js');
exported.processedList(storename, function(err, results) {
if (err) { console.log(err); }
console.log(results);
});
This makes sure that console.log happens only when processedList finishes execution.

Node js nested async call

I want to do async call from my getData function to getImage function but i am unable to get return data from getImage().Since the getData() does't wait for the completion of getImage(),as getImage() has further async db calls and therefore getData() always returns undefined.
What is the best way to do this instead doing nested callbacks?
var getData = function(id){
async.series([
function(callback){
var res = getImages(id);
callback(null, res);
}
],
// optional callback
function(err, results){
if (err) {
console.log("ERROR : " + err);
}else
{
console.log("Result: "+results);
}
});
}
var getImages = function(id){
async.series([
function(callback){
Image.find({id: id }).exec(
function(err, image) {
if (err) {
console.log(err);
callback(err, 0);
}else
{ console.log("Count: "+ image.length);
callback(null, image);
}
});
}
],
// optional callback
function(err, results){
if (err) {
console.log("ERROR : " + err);
}else
{
return results;
}
});
}
getData(1);
As you said you need to wait for getImages() to return, and you do that using promises.
Use any promise library, like q for instance:
var q = require('q')
...
var getImages = function(id){
var deferred = q.defer();
...
//do async logic that that evaluates some res obj you wish to return
db.find(..., function() {
deferred.resolve(res);
}
return deferred.promise;
}
Then, from getData(), you call it in the following matter:
getImages(id).then(
function(res) {
callback(null, res);
},
function(err) {
console.log("error:" + err);
}
);
As you are already using async - just use the waterfall functionality: https://github.com/caolan/async#waterfalltasks-callback
This way you will be able to run functions one after another and wait for the previous to finish, while still getting it's return value.

Check if user already exist and wait for callback

I have a small function to validate the user input. In that function I will also check if the email address is already taken. But I have some trouble with the async callback.
I hope anyone could give me a hint, how I could solve this. I use nodejs with the express 3 framework, mongodb and the node-validator library.
This is a part of my validation function:
function check(data, callback) {
mongoose.model('User', User).count(data, function (err, count) {
callback(err, !! count);
});
};
function validate(email, password, confirm) {
var v = new Validator(),
errors = new Array();
v.error = function (msg) {
errors.push(msg);
};
check({email: email}, function (err, exists) {
v.check(exists, { email: 'E-Mail is already taken' }).equals(false);
});
...
return errors;
}
Based on the async callback the variable errors is at the return statement empty. How could I else check if the email address is already in the databse?
You are going to have to add a callback to your validate function. As it stands now, your check function is asynch so you are immediately returning the empty errors array.
function check(data, callback) {
mongoose.model('User', User).count(data, function (err, count) {
callback(err, !! count);
});
};
function validate(email, password, confirm, callback) {
var v = new Validator(),
errors = new Array();
v.error = function (msg) {
errors.push(msg);
};
check({email: email}, function (err, exists) {
if (err) {
return callback(err);
}
v.check(exists, { email: 'E-Mail is already taken' }).equals(false);
callback(null, v);
});
};
// Calling to validate example
server.get("/validate_user_or_whatever", function(req, resp) {
// Call validate with callback
validate(req.param("email"), req.param("password"), true, function(err, validator) {
if (err) {
return resp.json({success: false, message: err.message});
}
var success = validator.isValid; // or something
// Respond with the results
resp.json({success: success});
});
});
Now, your next question is probably going to be how do I run all these validate functions and wait for them to return before calling the validate callback. Good question, take a look at the async module.
You need to think async and pass callbacks that will be called asynchronously.
Quick example:
app.get('/blah', function(req, res) {
// Whatever
validate(email, pass, confirm, function(errors) {
if (errors.length == 0)
resp.send(200, 'blah');
else
resp.send(400, 'blah blah');
});
})
function validate(email, password, confirm, callback) {
var v = new Validator(),
errors = new Array();
v.error = function (msg) {
errors.push(msg);
};
check({email: email}, function (err, exists) {
v.check(exists, { email: 'E-Mail is already taken' }).equals(false);
}, function() {
callback(errors);
});
// ...
return errors;
}

Resources