1
votes

In my application I would like to query items that are close by (e.g. within 5km) to a coordinate and I tried to use $near to achieve that. With a quick look I thought it worked but after I tested it further it seems the query is somewhat inaccurate. Here is my setup:

  1. I selected 2 coordinates that are a bit less than 5km apart from each other:

    • 61.4644750214197, 23.8426943813556
    • 61.497133399999996, 23.778528100000003

(At least according to tools like this, this or this the distance between those coordinates should be about ~4,99km)

  1. I added one of the coordinates into empty "items" collection:
db.items.insert({
    "geo" : {
        "type" : "Point",
        "coordinates" : [ 
            61.4644750214197, 
            23.8426943813556
        ]
    }
});
  1. I added "2dsphere" index to the collection make geospatial queries possible:
db.items.createIndex( { geo : "2dsphere" } )
  1. Finally, I used the other coordinate with $near query:
db.items.find({geo: {
    $near: {
        $geometry: {
            type: "Point" ,
            coordinates: [ 61.497133399999996, 23.778528100000003 ]
        },
        $maxDistance: 5000 // according to docs with '2dsphere' index and GeoJSON this is is meters
    }
}}).count()
  1. I expected the result to be 1 but instead it is 0. Even if I set $maxDistance to 7000 the result is still 0, but if I set it to 8000 the result will be 1.

Am I doing something wrong or are MongoDB geospatial queries (or just $near query?) that inaccurate? If so, is there a better way to get accurate results for this kind of query? This is my first time dealing with geospatial queries in MongoDB so there is probably a trivial explanation for my problem.

EDIT: Basically I was dreaming of a functionality to show all items in map within X kilometres from users current location and X could be determined by user. It would be awkward if an item within 5km would not be visible even when the user wants to filter items within 7km.

I have tried most of the options for doing this query, like $centerSphere, $nearSphere and geoNear with similar results. They all seem to claim that the distance between my earlier mentioned coordinates is somewhere between 7-8km. I'm starting to think either 1. I'm missing some key peace of information about how distances work in general or 2. it simply is not possible to solve my problem with . Below are my queries for the other options:

$centerSphere (0 results with 5, 6 and 7km but 1 result with 8km):

db.items.find( { geo: { 
        $geoWithin: { $centerSphere: [ [ 61.497133399999996, 23.778528100000003 ], 5/6378.1 ] 
    }
}}).count()

geoNear (0 results with maxDistance 5000, 6000 and 7000 but 1 result with 8000):

db.runCommand(
   {
     geoNear: "items",
     near: { type: "Point", coordinates: [ 61.497133399999996, 23.778528100000003 ] },
     spherical: true,
     maxDistance: 5000
   }
)
1
$nearSphere is the operator for actually considering the curvature of the earth. I thought there was a reference to that on the $near operator, but there does not appear to be. - Neil Lunn
And yes there is a "built in error" with the math on geospatial queries. The earth isn't "really" a sphere and you have to expect error. But it should be within 5 meters - Neil Lunn
@NeilLunn In this case with $nearSphere I get identical results as with $near. - Timo Ruostila
On the same coordinates that is not surprising. The point is if you want "real" distances that will be what you use. But the "error" is still inherrent to any geospatial calculation. There's lots of reading you have do on haversine and the like algorithms. - Neil Lunn
Thanks @NeilLunn for the replies! I read your original comment again and I get your point now. Still I think the reason for me getting 0 results with $maxDistance values 5000, 6000 and 7000 in the query is left unexplained: the accuracy "error" is far more than 5m in this case. - Timo Ruostila

1 Answers

3
votes

I understand I am late to the party, but for all those who are facing similar issue

The problem here is that when you store that data into "coordinates", it must be in the [longitude, latitude] order because this is how mongodb works. https://docs.mongodb.com/manual/geospatial-queries/#spherical I just ran your example with reversed order of coordinates and it worked as expected.

db.items.insert({
    "geo" : {
        "type" : "Point",
        "coordinates" : [ 
            23.8426943813556,
            61.4644750214197
        ]
    }
});

And then i ran

db.items.find({geo: {
    $near: {
        $geometry: {
            type: "Point" ,
            coordinates: [  23.778528100000003 , 61.497133399999996]
        },
        $maxDistance: 5000
    }
}}).count()

The count here is 1:

Hope it helps