I've run into an issue and I'm unsure what steps to take to fix it. Right now all the data is being correctly retrieved however the responseCallback is never firing and thus i'm not reaching the res.json call with the response array. Any guidance here would be greatly appreciated! Thanks.
For clarification the problem is with the aysnc.each callback.
var updatedBusinesses = [];
googleplaces.radarSearch({location:"lat,long",radius:"10000",keyword:"keywordhere"},function(err,response){
if(err){return next(err);}
async.each(response.results,function(currResponse,responseCallback){
Business.findOne({"placesId":currResponse.place_id,"claimed":true}).populate({path:'services',select:''}).exec(function(err,business){
if(err){return next(err);}
if(business !== null){
Service.populate(business.services,{path:'employees',select:'_id appointments firstName lastName username avatarVersion'},function(err,newBusiness){
if(err){return next(err);}
googleplaces.placeDetailsRequest({placeid:business.placesId},function(error,placesResult){
if(error){return responseCallback(error);}
console.log("RESULT OF THE GOOGLE PLACES DETAIL SEARCH")
placesResult.result.info = business;
updatedBusinesses.push(placesResult.result);
// Here the data is populated and correct.
// console.log(updatedBusinesses)
responseCallback();
});
})
}
})
},function(err){
if(err){return next(err);}
console.log("called")
res.json(updatedBusinesses);
})
})
This is where I'm hoping to return the updated business information to the client however this never fires.
},function(err){
if(err){return next(err);}
console.log("called")
res.json(updatedBusinesses);
})
})
async.each() expects a callback (responseCallback) to be called for every iteration. If it's not called, it's sitting there waiting for it. That's why your update business section never gets called.
Inside your async.each(), there are a number of places calling next() which is not async.each()'s iteration's callback (responseCallback). Here is the revised code that calls the callbacks properly:
var updatedBusinesses = [];
googleplaces.radarSearch({location:"lat,long",radius:"10000",keyword:"keywordhere"},function(err,response){
if(err){return next(err);}
async.each(response.results,function(currResponse,responseCallback){
Business.findOne({"placesId":currResponse.place_id,"claimed":true}).populate({path:'services',select:''}).exec(function(err,business){
if(err){
return responseCallback(err);// <== calling responseCallback instead of next()
}
// in case of business === null/undefined, I'm not seeing any
// callback getting called, it needs to be called inside
// async.each() no matter which condition it is
if (!business) {
// call responseCallback to continue on with async.each()
return responseCallback();
}
Service.populate(business.services,{path:'employees',select:'_id appointments firstName lastName username avatarVersion'},function(err,newBusiness){
if(err){
return responseCallback(err);// <== calling responseCallback instead of next()
}
googleplaces.placeDetailsRequest({placeid:business.placesId},function(error,placesResult){
if(error){return responseCallback(error);}
console.log("RESULT OF THE GOOGLE PLACES DETAIL SEARCH")
placesResult.result.info = business;
updatedBusinesses.push(placesResult.result);
// Here the data is populated and correct.
// console.log(updatedBusinesses)
responseCallback();
});
})
})
},function(err){
if(err){return next(err);}
console.log("called");
res.json(updatedBusinesses);
});
});
So now responseCallback() is called for every condition inside async.each(). It should get down to "updated business information" part of the code now.
Changing your code responseCallback(); with responseCallback(null, [your-result]); I think should do the job
var updatedBusinesses = []; googleplaces.radarSearch({location:"lat,long",radius:"10000",keyword:"keywordhere"},function(err,response){
if(err){return next(err);}
async.each(response.results,function(currResponse,responseCallback){ Business.findOne({"placesId":currResponse.place_id,"claimed":true}).populate({path:'services',select:''}).exec(function(err,business){
if(err){return next(err);}
if(business !== null){
Service.populate(business.services,{path:'employees',select:'_id appointments firstName lastName username avatarVersion'},function(err,newBusiness){
if(err){return next(err);}
googleplaces.placeDetailsRequest({placeid:business.placesId},function(error,placesResult){
if(error){return responseCallback(error);}
console.log("RESULT OF THE GOOGLE PLACES DETAIL SEARCH")
placesResult.result.info = business;
updatedBusinesses.push(placesResult.result);
// Here the data is populated and correct.
// console.log(updatedBusinesses)
responseCallback(null, updatedBusinesses);
});
})
} }) },function(err, updatedBusinesses){
if(err){return next(err);}
console.log("called")
res.json(updatedBusinesses);
})
})
Related
Hello guys I am trying to manipulate the documents that I am inserting to my collection with the create().Essentially I am calling a function that increments a letter field.
My pre hook is like
baseAttribute.pre('save',async function(next){
var att=this;
const query=await mongoose.models.BaseAttributes.find({},{},{sort:{_id:-1}}).limit(1)
console.log(query)
if(query.length===0)
{
att.code="AA"
}else{
att.code= Codes.GetAlphaCode(query[0].code);
}
next()
})
The result is that all the documents inserted by the create function are getting the same code
I found a solution to the problem.
// asyncs because I am not sure if it will cause a conflict with my async functions
var asyncs = require("async");
asyncs.eachOfSeries(newArray,function (item, i, next){
// console.log(item)
console.log("In each async")
// item.save(next);
BaseAttribute.find({},{},{sort:{_id:-1}}).limit(1).then(result=>{
console.log("In find")
if(!result[0]){
item.code="AA"
}else{
item.code=Codes.GetAlphaCode(result[0].code)
}
item.save(next);
})
}, function(err) {
if (err) return console.log(err);
res.json({done:"true"})
});
This is the way save documents one by one (in a serial order).
I query one collection (messages) with mongoose. The result is an array of documents. Each document contains an ID for a different collection (users). Now I want to query the users collection for each ID from the messages collection.
The idea is to update each message object with the information from the user collection before returning it to the front end.
I tried using async.each. For some reason the final function is never called even though I am making sure the callback() function is called after each iteration.
app.get('/getmsg', function(req, res){
messages.find({query})
.exec(function(err, ms){
if(err) throw err;
async.each(ms, function(m, callback){
users.findOne({_id : m.userId})
.lean()
.exec(function(err, user){
if(err) {
console.log('error' , err);
callback();
} else {
m.userName = user.name;
// everything is working up to here
callback();
}
}), function(err){
res.send(ms); // this is never returned!
}
});
});
});
Is there a better way of achieving this? I assume this must be a common issue.
Thanks!
You can't use res.send. Instead create a function to get notified about it. Something like this.
// 1st para in async.each() is the array of items
async.each(items,
// 2nd param is the function that each item is passed to
function(item, callback){
// Call an asynchronous function, often a save() to DB
item.someAsyncCall(function (){
// Async call is done, alert via callback
callback();
});
},
// 3rd param is the function to call when everything's done
function(err){
// All tasks are done now
doSomethingOnceAllAreDone();
}
);
I have an async.eachSeries() function which process a list of objects. After the list I want a res.send() function so I can send the result back to the frontend.
But I'm getting a
'Can't set headers after they are sent'
error on the res.send() line, which it's looks that the function is called before the list is completely processed.
module.exports.createOrder = function(req,res){
console.log("CreateOrder");
var orderDescription = "";
var payId = new ObjectId(); //create one id, to pay multiple orders at one time
var shopList = groupByShop(req.body.cart);
var orders = [];
var result = {};
console.log("before async");
//the cart is now sorted by shop, now we can make orders for each shop
async.eachSeries(Object.keys(shopList), function(key, callback){
console.log("in async");
var shop = shopList[key];
console.log("before saveOrder");
saveOrder(payId, shop, key, req.body, req.user, function(err, newOrder){
console.log("in saveorder");
if(err){
console.log("Err", err);
callback(err);
}else{
console.log("order saved");
orders.push(newOrder);
callback();
}
})
}, function(err){
if(err){
console.log("One or more orders are not saved:", err);
return res.status(400).json(err);
}else{
console.log("All orders are processed");
result = {
message: 'OK',
order: {
payId: orders[0].payId
}
};
return res.send(200).json(result);
}
})
}
What is going wrong here? Currently testing with one object in the 'shopList', and all log lines are visible in the server console.
When I remove the line, the function is working fine, but, of course, he is not sending any results. I also tried to move the line outside the function, but that cause, of course again, in a empty result{} and a sending before the function is done.
res.send(200) will send a HTML response with content '200' - what you want to do is res.status(200).json(result) although res.json(result) should also work fine.
Im trying to implement some way to stop my code to redirect me before I get the response from the omdb api I am using.
My function for making a search for a movie and saving all titles in a session looks like this:
app.post('/search', isLoggedIn, function(req, res) {
function getMovies(arg, callback){
console.log('In getMovies');
console.log('searching for '+arg);
omdb.search(arg, function(err, movies) {
if(err) {
return console.error(err);
}
if(movies.length < 1) {
return console.log('No movies were found!');
}
var titles = [];
movies.forEach(function(movie) {
// If title exists in array, dont push.
if(titles.indexOf(movie.title) > -1){
console.log('skipped duplicate title of '+movie.title);
}
else{
titles.push(movie.title);
console.log('pushed '+movie.title);
}
});
// Saves the titles in a session
req.session.titles = titles;
console.log(req.session.titles);
});
// Done with the API request
callback();
}
var title = req.body.title;
getMovies(title, function() {
console.log('Done with API request, redirecting to GET SEARCH');
res.redirect('/search');
});
});
However I dont know if I implement callback in the right way, because I think there can be a problem with the api request actually executing before the callback, but not finishing before. And therefor the callback is working..
So I just want 2 things from this question. Does my callback work? And what can I do if a callback won't solve this problem?
Thankful for all answers in the right direction.
Add
callback();
To, like this
omdb.search(arg, function(err, movies) {
if (err) {
return console.error(err);
}
if (movies.length < 1) {
return console.log('No movies were found!');
}
var titles = [];
movies.forEach(function(movie) {
// If title exists in array, dont push.
if (titles.indexOf(movie.title) > -1) {
console.log('skipped duplicate title of ' + movie.title);
} else {
titles.push(movie.title);
console.log('pushed ' + movie.title);
}
});
// Saves the titles in a session
req.session.titles = titles;
callback();
});
omdb.search is asynchronous function that's why callback executed before omdb.search
The console statement never prints. I am not sure why. I am writing a function to list all characters (one user has many characters). The function isn't fully written yet. It simply returns the user with the specified email.
For some reason though it never returns. It outputs "This statement prints" But never the "why doesn't this ever print" statement!
UserSchema.methods.usersCharacters = function(email,cb){
User.findOne( {'local.email' : email }).exec(function(err, user){
if (err) console.log("oops");
console.log("This statement prints");
return user;
});
};
UserSchema.methods.usersCharacters('a#gmail.com', function(err, okay){
console.log("Why doesn't this ever print?");
});
I needed to call the callback! DANGIT!
You need to call the callback ,see this :
var a = function(input ,callback){
if ( input == "true" ){
callback(null ,"it's true");
} else {
callback(true ,"it's false")
}
};
a(true ,function(err ,res){
console.log(err);
console.log(res);
});
a(false ,function(err ,res){
console.log(err);
console.log(res);
});
I hope this help you to understand how to write callbacks.