MongoDB $centerSphere vs Redis geospatial - mongodb

I want to show nearby places on the map for a given user.
I can do so either by query MongoDB like this:
db.places.find( {
loc: { $geoWithin: { $centerSphere: [ [ -88, 30 ], 10/3963.2 ] } }
} )
and either by query a Reids geospatial set like this:
georadius key longitude latitude 100 m
Any pros and cons?

Related

MongoDB $near query accuracy issue

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:
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)
I added one of the coordinates into empty "items" collection:
db.items.insert({
"geo" : {
"type" : "Point",
"coordinates" : [
61.4644750214197,
23.8426943813556
]
}
});
I added "2dsphere" index to the collection make geospatial queries possible:
db.items.createIndex( { geo : "2dsphere" } )
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()
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 mongodb. 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
}
)
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

MongoDB: Select all polygons within the radius of a point

I have two collections in my database: Post and Gallery. A Post has a single GeoJSON Point location, and a gallery is a collection of posts. The gallery's location is a GeoJSON Polygon bounding the gallery's posts (using quickhull algorithm). I now need to query for all galleries within x miles of a certain point, however I'm not getting any results even if I query from right next to my polygon.
I would like the behavior to be exactly the same as the following:
db.posts.find({
'location': {
$geoWithin: {
$centerSphere: [[-70, 30], 1000/3959]
}
}
});
Here, all posts within a the radius are returned. However, when I run the same type of function in this way, I am returned nothing, which is not correct:
db.galleries.find({
'location': {
$geoWithin: {
$centerSphere: [[-70, 30], 1000/3959]
}
}
});
One of my galleries has the following location (is 2dsphere index with 2dsphereIndexVersion = 2):
"location": {
"type": "Polygon",
"coordinates": [
[
[
-73.986882,
40.682829
],
[
-73.971089,
40.6672045
],
[
-73.955296,
40.65158
],
[
-73.986882,
40.682829
]
]
]
}
How do I query for location polygons that at least intersect with my radius?
I had the same problem and tried the exact same query that you initially tried. I'm not sure why it didn't work, but I was eventually able to get $near to do the job. Keep in mind that $near uses meters when calculating $maxDistance, so I had to convert my 10 mile desired distance to meters by multiplying by 1609.34. Here's the query that I ended up using:
db.maTowns.find(
{
'geometry': {
$near: {
$geometry: {
'type': "Point",
'coordinates': [ -71, 42 ]
},
$maxDistance: 10 * 1609.34
}
}
}
)
Select all polygons within the radius of a point
With the recent release of MongoDB version 3.6.0-rc0, you can now query GeoJSON LineStrings and Polygons with $geoWithin geospatial operator $centerSphere.
See also SERVER-27968 for more information about the change. Note that this change is pending to be backported.
Also maybe related for $geoIntersects and $centerSphere is ticket SERVER-30390

How to get unique mongodb?

If I have documents like this:
{firstname:"Jordan", lastname:"Snyder", age:6, homelocation:[<longitude, latitude>]}
In the mongo shell, how do I all the "distinct" firstname's across matching documents of people who live near a specific point (say 1 mile)? I see mongo has a distinct db.collection.distinct(field, query), but all the samples I see for finding anything "near" or "geowithin" (using homelocation field in my case) is using db.collection.find. I don't want all documents, I just want the distinct list of firstnames.
The query parameter of distinct uses the same format as the query selector parameter of find. So assuming a 2dsphere index on homelocation you can do something like:
db.test.distinct('firstname', {
homelocation: {
$near: {
$geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
$maxDistance: 1600 // In meters
}
}
})

Mongodb geospatial query performance

I am writing a nodejs app involving geocodes ( ~50million places) stored in mongodb (using mongo native driver). For development I am testing with sample data (airports of the world ~45k locations http://www.ourairports.com/data/airports.csv ). I am following GeoJSON format and building 2dsphere index on location field(named "geometry"). Then I am doing a $geowithin query to find locations.
Evrything works as expected. The issue is that when I am querying for a polygon containing US, the query is taking around 4-6sec for returning 22845 locations.
db. airports.ensureIndex({ geometry: '2dsphere' })
db.airports.find({ geometry: { '$geoWithin': { '$geometry': { type: 'Polygon', coordinates: [ [ [ -127.32917843921399, 75.11297289119061 ], [ -71.32126356078601, 75.11297289119061 ], [ -71.32126356078601, 12.305525108809391 ], [ -127.32917843921399, 12.305525108809391 ], [ -127.32917843921399, 75.11297289119061 ] ] ] } } } })
I am sure that this cant be correct. This way I cant imagine response times with 50million points.
Would appreciate if someone can point me in direction to improve the performance of this.

Does MongoDB support GIS geofencing with $geoWithin?

I would like to have a MongoDB collection and each document contains a geospatial polygon defined by latitude/longitude points (in GeoJSON). Then, I would like to take any given longitude/latitude point and check if it resides within any of the MongoDB polygons defined in the documents. Hypothetically, this is what the documents would look like.
{
"type" : "congressional",
"points" : [
{ "coords" : [
-141.0205,
70.0187 ]
},
...
{ "coords" : [
-141.0205,
70.0187 ]
}
]
}
Or maybe like so:
{ loc :
{ type : "Polygon" ,
coordinates : [ [ [ 0 , 0 ] , [ 3 , 6 ] , [ 6 , 1 ] , [ 0 , 0 ] ] ]
} }
And then I would query it, hypothetically, like so (most likely with Mongo's $geoWithin):
db.places.find( { loc : { $geoWithin : { $geometry : "EACH DOCUMENT IN COLLECTION"} } } )
Is geofencing, or something similar, possible to do with the current MongoDB feature-set? If so, how would it be done?
I believe you would have to first find every document from the collection., and then make a "$geoWithin" query for every document, passing in the Polygon to test against for each case.
Depending on the number of documents in your collection, that may or may not provide sufficient performance.
MongoDB has full support for geofencing or finding documents whose geometry intersects with a given geometry (point, polygon). The query below is an example. geometry of Collection is the field containing the geometry.
Document Example:
{ "geometry": {
"type": "Polygon",
"coordinates": [
[
[
-74.001487,
40.692346
],
[
-74.001755,
40.692057
],
[
-74.000977,
40.691951
],
[
-74.000827,
40.692297
],
[
-74.001487,
40.692346
]
]
]
}
}
JS Query:
//find quests bots that matches the users location
await Collection.find({ geometry:
{ $geoIntersects:
{
{
type: "Point",
coordinates: [
-73.99460599999999,
40.7347229
]
}
}
}
});