Reputation: 520
Given a schema defined for documents containing a GeoJSON location;
var BranchSchema = new Schema({
location: {
'type': {
type: String,
required: true,
enum: ['Point', 'LineString', 'Polygon'],
default: 'Point'
},
coordinates: [Number]
},
name: String
});
BranchSchema.index({location: '2dsphere'});
And some sample data:
[
{
"name": "A",
"location": {
"type": "Point",
"coordinates": [153.027117, -27.468515 ] //Brisbane, Australia
}
},
{
"name": "B",
"location": {
"type": "Point",
"coordinates": [153.029884, -27.45643] //Also Brisbane, Australia
}
}
]
The following geoNear query is not behaving as expected. I read this query as "given a location off the coast of South America, trawl through the locations and find any that are within 1 meter of the provided location."
// Somewhere off the east coast of South America.
var point = {type: 'Point', coordinates: [0.0776590, -33.7797590]};
Branch.geoNear(point, {maxDistance:1, spherical: true}, function (err, data) {
...
// at this point I expected data.length === 0.
// Instead it is returning both documents.
...
});
What am I doing wrong?
Upvotes: 4
Views: 8448
Reputation: 1585
Mongoose was converting geoJSON points to legacy coordinate pairs due to a limitation in the native driver; support has been added to the native driver, and there's an open PR to add this support to Mongoose. Ive updated the issue provided by @NickB.
Upvotes: 2
Reputation: 520
The problem was incorrectly using maxDistance. The following expression worked.
Branch.geoNear({type: "Point", coordinates: [0.0776590, -33.7797590]}, {
spherical: true,
maxDistance: 1 / 6378137,
distanceMultiplier: 6378137
})
.then(function (doc) {
console.log(doc);
process.exit();
});
Mongoose: branches.ensureIndex({ location: '2dsphere' }) { safe: undefined, background: true }
Mongoose: branches.geoNear(0.077659) -33.779759 { distanceMultiplier: 6378137, lean: true, maxDistance: 1.567855942887398e-7, spherical: true }
[]
Now the query correctly discovers that the two documents in the collection are not within 1 meter of the queried location. Querying a location closer to home also gives us the expected results.
Branch.geoNear({type: "Point", coordinates: [153.027117, -27.468515]}, {
spherical: true,
maxDistance: 1 / 6378137,
distanceMultiplier: 6378137
})
.then(function (doc) {
console.log(doc);
process.exit();
});
Mongoose: branches.ensureIndex({ location: '2dsphere' }) { safe: undefined, background: true }
Mongoose: branches.geoNear(153.027117) -27.468515 { distanceMultiplier: 6378137, lean: true, maxDistance: 1.567855942887398e-7, spherical: true }
[ { dis: 0.0026823704060803567,
obj:
{ name: 'A',
_id: 533200e49ba06bec37c0cc22,
location: [Object],
__v: 0 } } ]
The solution?
MongoDb documentation of geoNear states that if using a geoJSON object maxDistance should be in meters, and in radians if using coordinate pairs.
Optional. A distance from the center point. Specify the distance in meters for GeoJSON data and in radians for legacy coordinate pairs. MongoDB limits the results to those documents that fall within the specified distance from the center point. http://docs.mongodb.org/manual/reference/command/geoNear/#dbcmd.geoNear
This is either wrong, or my understanding of it is wrong.
As you can see above, rather than specifying 1 meter for maxDistance, it is supplied in Radians.
As at the date of this post geoNear requires that maxDistance be in Radians regardless of whether you are using a geoJSON object or a legacy coordinate pair.
Upvotes: 4