Reputation: 2031
I have a problem which has already cost me a couple of days and I totally fail to understand it. I use node.js and have a mongodb with places indexed for their coordinates. I verified that the index works fine beforehand. For a set of coordinates, I want to find the nearest place. Here's how I tried to go about it:
var Places = require(./models/places.js),
coordFinder = require('./coordFinder.js');
...
function getCoords(userId, callback) {
coordFinder.getCoords(userId, function(err, coords) {
if (err) {
callback(err);
} else {
callback(null, coords);
}
}
}
function getNearestPlaces(coords, callback) {
async.forEachSeries(
coords,
function(coord, done) {
Places.findOne(
{ coordinates: { $near: [ coord.lat, coord.lon ] } },
function(err, place) {
// do something with place
done();
}
)
},
function(err) {
callback(err ? err : null);
}
);
}
...
async.waterfall(
[
...
getCoords,
getNearestPlaces,
...
],
function(err) {
...
}
}
The mongodb query consistently fails with the following error message for the first query:
RangeError: Maximum call stack size exceeded
When I change the query in getNearestPlaces
to
... { $near: [ 10, 10 ] } ...
I as consistently get no error and the correct place. The same happens if I avoid the call to coordFinder
in getCoords
and change getCoords
to
function getCoords(userId, callback) {
callback(
null,
[
// some coordinates
]
);
I know the error indicates a stack overflow (increasing the stack size didn't help) but I can't figure out how I could have caused one. Does anyone have a clue as to why this happens? Thanks in advance for your insights!
Edit: It got the same problem when using mongodb-native
directly, by the way, so mongoose
seems not to be the problem. One more clue - using the same query never gives me a problem when I don't call it from within a callback. Could that be a source of error?
I use
Cheers, Georg
Upvotes: 1
Views: 637
Reputation: 2031
mjhm pointed me in the right direction. Apparently, the Number instanced passed to the mongoose query caused the stack overflow. I'm not sure why, but creating a new Number object from the old one (as mjhm suggested) or converting the number into a primitive with valueOf() solved the problem.
If anyone has a clue as to how the original Number object caused the stack overflow, I'd very much appreciate any insights you might have to offer.
Upvotes: 1
Reputation: 16695
The problem is most likely coming from the hidden recursion of async.forEachSeries
. Try wrapping the Places.findOne
call with setTimeout
like this:
function getNearestPlaces(coords, callback) {
async.forEachSeries(
coords,
function(coord, done) {
setTimeout(function () {
Places.findOne(
{ coordinates: { $near: [ coord.lat, coord.lon ] } },
function(err, place) {
// do something with place
done();
}
);
}, 1);
},
function(err) {
callback(err ? err : null);
}
);
}
This puts the Places.findOne
call outside of the call stack of async.forEachSeries
.
Upvotes: 2