Mongoose findOne not finishing callback function - javascript

Ok I have a JS method that uses Lodash and mongoose to find docs in a Mongoose collection. This looks fine, but it that appears to not finish the callback function before moving on to the next doc to look for. Below is my function:
importParts: function(participants, event_id, done){
_.forEach(participants, function (participant) {
var race = {event_id: event_id, chip_number_64: participant.chip_number_64};
Runner.findOne({contact_id: participant.contact_id}, function (err, doc) {
if (err) {
logger.error('CANNOT FIND AND UPDATE RUNNER BECAUSE OF: ', err);
done(err);
}
logger.info("IN FINDONE");
if (doc === null) {
logger.info("IN FINDONE1");
participant.races = [race];
Runner.create(participant, function (err, row, rowsAffected) {
if (err) {
logger.error('FAILED TO IMPORT PARTICIPANT: ', doc);
logger.error(err);
done(err);
}
logger.info("IN FINDONE2");
});
}
});
};
done(null);
}
For some reason the above code does not honor the callback function and appears to asynchronously return back to the main method that is calling this one. It's as if the callback is not being honored till after a set amount of time or something is happening asynchronously that shouldn't because I have everything wrapped in callbacks. So I am just trying to find out why the callback isn't completing when the query is executed? Also, this still happens even without the forEach iteration included in above code.

Related

How to promisify a function who doesn't necessary invoke its callback?

Consider a function like this:
function fetchUser(userId, cb) {
db.getUserById(userId, function(err, user) {
if (err)
return cb(err)
if (!user)
return // Pay attention to this line
return cb(null, user)
});
}
How would you promisify such a function.
Precisely, how would you deal with the simple return; statement that doesn't call the callback ?
Should this be a promise that stay in a pending state forever ? Doesn't feel right somehow

Error only callback in async npm module

I am using this async module for asynchronously requesting
web content with the help of another module request, as this is an asynchronous call.
Using async.each method, for requesting data from each link,
the result is also successfully returned by the scrap() function (which I have wrote to scrap returned html data
and return it as array of fuel prices by state).
Now, the problem is that when I try to return prices back to async.each() using cb(null, prices), it shows console.log(prices) as undefined
but logging inside the _check_fuel_prices(), works fine. It seems the callback works with only one argument
(or error only callback, as show as an example in the async.each link above). What if I want to it return prices (I can change it with error like cb(prices), but I also want to log error).
router.get('/someRoute', (req, res, next) => {
const fuels = ['diesel', 'petrol'];
async.each(fuels, _check_fuel_prices, (err, prices) => {
if (!err) {
res.statusCode = 200;
console.log(prices);
return res.json(prices);
}
res.statusCode = 400;
return res.json(err);
});
function _check_fuel_prices(fuel, cb) {
let prices = '';
const url_string = 'http://some.url/';
request(`${url_string}-${fuel}-price/`, (error, response, html) => {
if (error) {
cb(error, null);
return;
}
if (response.statusCode === 404) {
console.log(response.statusCode);
cb('UNABLE TO FIND PAGE', null);
return;
}
prices = scrap(html, fuel);
console.log(prices);
cb(null, prices);
return;
});
}
});
As #generalhenry points out, I was able to get the prices by using async.map which returns error first callback instead of error only apart from that async.series can be used here by slightly changing the code.

Node js: Express js asynchronous db query execution-return results got undefiend

Just started to learn express js framework ,here is my simple database query execution part its invoked with this url localhost:3000/api/test.
db.query('SELECT * FROM user', function (error, results, fields) {
if (error) throw error;
console.log('The result is:', results[0].id);
return results;
});
Does it really asynchronous?? suppose another user request this url does he need to wait for the previous query execution??.
I've heard about async package ,but don't know how this is applicable in my case
UPDATE
I got proper result in console.log(); but when i return the result i got undefined error
Here is my model.js
module.exports = {
getUser:function () {
db.query('SELECT * FROM user', function (error, results, fields) {
if (error) throw error;
console.log('The result is: ', results[0].id);
});
}
}
From my controller.js
var model = require('../models/user.js');
module.exports = {
getData : function(req, res){
//invoke model
console.log(model.getUser());
}
}
Node is non-blocking and will serve this request as and when it's called.
If another user hits this endpoint then it will execute again regardless if the first query has completed or not (unless the SQL has locked the table, in which case all consecutive connections/queries will wait and may timeout because of it). This happens on a connection basis.
You should make sure to check your SQL server (MySQL?) configs here to make sure there are enough max_connections to be able to cope with whatever load you are expecting.
Remember that the biggest bottleneck to an application is usually the database.
Your query above will need a callback to return the data asynchronously.
db.query('SELECT * FROM user', function (error, results, fields) {
if (error) throw error;
console.log('The result is:', results[0].id);
//cb=callback function passed in to context
if (cb) cb(results);
});
Updated answer from updated question
In your model.js:
module.exports = {
getUser:function (cb) {
db.query('SELECT * FROM user', function (error, results, fields) {
if (error) throw error;
console.log('The result is: ', results[0].id);
if (cb) cb(results);
});
}
}
In your controller.js:
module.exports = {
getData : function(req, res){
//invoke model
model.getUser(function(results) {
console.log(results);
});
}
}
When you deal with callback, the safe and clean way to handle them is Promises. It's now standard in JavaScript and don't require any module.
And yes it is asynchronous. Behind, there'll be network access and dialogs with the database server. Only when they're done chatting will the callback be called.
module.exports = {
getUser: function () {
// wrap asynchronously called callback in Promise
new Promise((resolve, reject) => {
db.query("SELECT * FROM user", (error, results, fields) => {
if (error) {
reject(error); // similar to "throw"
}
else {
resolve({ results, fields }); // similar to "return"
}
});
});
}
};
How do you use it:
Vanilla notation:
// similar to "try"
model.getUser()
.then((answer) => {
console.log("answer", answer);
})
// similar to "catch"
.catch((error) => {
console.log("error", error);
});
async-await notation (only available in last versions of nodejs & browsers):
// you must be in an async environement to use "await"
async function wrapper() {
try {
var answer = await model.getUser(); // wait for Promise resolution
console.log("answer", answer);
}
catch(error) {
console.log("error", error);
}
}
// async function return automatically a Promise so you can chain them easily
wrapper();

NodeJS async callbacks not firing

I'm working with NodeJS and the Async api to create an api function that returns a list of stories. The get can be shallow (only contains Object ID's referencing other objects) or deep (all ID references are dereferenced by replacing the ID with the object referenced by it). The shallow get works fine, however when I run the deep copy, it hangs. You can see in my callbacks I placed console.log(#) to log which callback is fired, but none are fired.
I feel like the issue lies within if I'm mistaking how async handles the callback function parameter for the .each, .serial and .parallel functions. I need a function that will be fired once async completes all of its tasks, but the callback function is instead called after every operation each, serial or parallel completed.
router.get('/stories', function(req, res, next) {
var db = req.db,
options = {
deep : req.query.deep != null ? parseInt(req.query.deep) : false,
offset : req.query.offset || 0,
limit : req.query.limit || 0
};
Story.listStories(db, options, function(err, stories){
if (!options.deep){
res.json(new Response(err, stories));
res.end();
}else{
if (err || stories == null){
res.json(new Response(err, null));
res.end();
return;
}
async.each(stories,
function(story, cb1){
var articles = [],
galleries = [];
async.series([
function(cb2){
async.parallel([
//Extract the story's articles and their outlets
function(cb3){
async.each(story.articles,
function(article_id, cb4){
Article.getArticle(db, article_id, function(err, article){
if (err){
cb4(err);
return;
}
Outlet.getOutlet(db, article.outlet, function(err, outlet){
if (err){
cb4(err);
return;
}
article.outlet = outlet;
articles.push(article);
});
});
},
function(err){console.log(4);
if (err)
cb3(err);
});
}
],
function(err){console.log(3); //Parallel callback
if (err)
cb1(err);
});
},
function(cb2){
story.articles = articles;
}
],
function(err){console.log(2);
if (err)
cb1(err);
});
},
function(err){console.log(1);
res.json(new Response(err, stories));
res.end();
}
);
}
});
});
You're calling those async callbacks (cb1, cb2, cb3, cb4, and etc) only for error cases. you need to call for non-error cases also. Example:
if (err) {
return cb1(err);
}
cb1(null); // or cb1()

How to stop writing nesting code in node-mysql ( node.js, express, mysql )

Each time I throw a query, the nest depth increase by one, just like the code below. If I knew how to define a query as a function not in the action, the readability of my code would increase.
exports.getAll = function (req, res) {
client.query('SELECT * FROM tag', function (err, result, fields) {
client.destroy();
if (err) {
throw err;
}
var tag = result[0].tag;
client.query('SELECT COUNT(follow_id) AS following_tag_num FROM follow WHERE user_id = ?', [req.session.user.user_id], function (err, result, fields) {
client.destroy();
if (err) {
throw err;
}
res.render('hoge', {
title: 'Welcome to Hoge',
userInfo: req.session.user,
tag: tag,
following_tag_num: result[0].following_tag_num
});
});
});
}
Just make the handler a named function:
client.query(
'SELECT COUNT(follow_id) AS following_tag_num FROM follow WHERE user_id = ?',
[req.session.user.user_id],
handleResult
);
function handleResult(err, result, fields) {
client.destroy();
if (err) {
throw err;
}
res.render('hoge', {
title : 'Welcome to Hoge',
userInfo : req.session.user,
tag : tag,
following_tag_num: result[0].following_tag_num
});
}
You might look into several node flow control modules that are available to help curb the nesting. I like one called async. It provides a variety of ways to de-nest your nested code.
var async = require('async');
async.waterfall([
function(callback) {
client.query(sql, callback);
},
function(results, callback) {
// do something with results, then call callback
}],
function(err, data) {
// if any errors occur above, err is not null
// otherwise 'data' is whatever got passed to the last callback
});
async.waterfall takes a list of functions, and passes the results of each one on to the next, finally calling the second parameter, another function, with the final result. Results are passed not by returning them, but by a callback function. async also supports running several functions in parallel, in series, and a variety of different common patterns used in node.

Categories