I'm trying to make use of some geolocation functionality in mongodb. Using a find query with $near doesn't seem to work!
I currently have this object in my database:
{
"Username": "Deano",
"_id": {
"$oid": "533f0b722ad3a8d39b6213c3"
},
"location": {
"type": "Point",
"coordinates": [
51.50998,
-0.1337
]
}
}
I have the following index set up as well:
{
"v": 1,
"key": {
"location": "2dsphere"
},
"ns": "heroku_app23672911.catchmerequests",
"name": "location_2dsphere",
"background": true
}
When I run this query:
db.collectionname.find({ "location" : { $near : [50.0 , -0.1330] , $maxDistance : 10000 }})
I get this error:
error: {
"$err" : "can't parse query (2dsphere): { $near: [ 50.0, -0.133 ], $maxDistance: 10000.0 }",
"code" : 16535
}
Does anyone know where I'm going wrong? Any help would be much appreciated!
It seems you need to use the GeoJSON format if your data is in GeoJSON format too, as yours is. If you use:
db.collectionname.find({
"location": {
$near: {
$geometry:
{ type: "Point", coordinates: [50.0, -0.1330] }, $maxDistance: 500
}
}
})
it should work. I could replicate your error using GeoJSON storage format for the field, but what the docs call legacy points in the query expression. I think the docs are a bit unclear in that they suggest you can use both GeoJSON and legacy coordinates with a 2dsphere index 2dsphere
I am using 2.4.10, for what it is worth, as there were some big changes to spatial in the 2.4 release.
This isn't exactly a solution as I never got the above working, but using geoNear I managed to get what I wanted.
db.runCommand( { geoNear : 'catchmerequests', near:
{ type: 'Point', coordinates : [50, 50] }, spherical : true } );
If anyone can find out why the original $near attempt failed that would still be appreciated, but I'm posting this for anyone else who else who is looking for a working alternative.
Related
I'm using MongoDB to store about 1 million documents representing regions.
Each document contains a coordinates record in the following format
"coordinates" : {
"longitude" : -77.02687,
"latitude" : 38.888565
}
Given a set of coordinates { x, y }, what query should I run to find the region ( document ) that is closest to it?
Based on the MongoDB geospatial-queries documentation the answer is quite simple.
In order to query for locations near a region you should follow these steps
Step 1
Create an index on the location field
db.places.createIndex( { location: "2dsphere" } )
Step 2
Find regions close to { -73.9667, 40.78 } ordered by closest locations
db.places.aggregate( [
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
spherical: true,
query: { category: "Parks" },
distanceField: "calcDistance"
}
}
] )
I am not sure if there is a way to do this. I need to have a circle in mongodb and run a query against that with a box using $box to see if these two shapes overlap or not. However, Geojson does not support circles. What would be the best way to get this done?
The circle is stored like this:
places = {
...
"location": {
"type": "Point",
"coordinates": [
-79.390756,
43.706685
]
},
"radius": 100
}
I have two specific problems:
The first issue is that maxDistance is stored in the same object as the Geojson object and cannot be used in a $near query with $maxDistance; it only takes a number.
I do a partial postal code/ zip code search on Google Geocoding Api which returns a box with two corner coordinates like this:
"geometry": {
"bounds": {
"northeast": {
"lat": 43.710565,
"lng": -79.37363479999999
},
"southwest": {
"lat": 43.690848,
"lng": -79.40025399999999
}
}
As far as I know,I cannot use $box as it only works with $geoWithin.
Edit 1:
My initial plan with the circle and the box changed mainly because I did not find a suitable and efficient solution to this problem. Instead of checking if the circle overlaps with the box, now I check if a Geojson point is inside the circle as follows:
db.places.aggregate([
{"$geoNear": {near: { type: "Point", coordinates: [ -80.459293, 40.713640] },
distanceField: "dist.calculated", maxDistance: 100000,
key: 'myLocation', query: { 'SomeField': "..." }, spherical: true}},
{ "$match" : {$expr:{ $lte:['$dist.calculated', 'radius']}}}])
The problem here is that I d have to run a query within 100 KM first and then in another stage of the aggregation check the distance.
Is there a more efficient way to implement this? Thanks.
You can store a circle as point and radius. And you can use a $near query with a point and $maxDistance in meters which is the radius of the circle. See MongoDB Documentation.
Query to find all location, geometry field of the collection, at a certain distance from a point.
db.places.find(
{
location:
{ $near :
{
$geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
$maxDistance: 5000
}
}
}
)
Query to find if a given geometry (point, polygon(rect too)) in a query intersects with a geometry of a field in the collection.
//find quests bots that matches the users location
await Collection.find({ geometry:
{ $geoIntersects:
{
{
type: "Point",
coordinates: [
-73.99460599999999,
40.7347229
]
}
}
}
});
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
I am experimenting with mongoDB geoNear query. I have a Collection with one document inside:
{
"_id": {
"$oid": "583d169df18ef10012ae8345"
},
"location": {
"loc": [
103.7652117,
1.3150887
],
"name": "",
"_id": {
"$oid": "583d169df18ef10012ae8346"
}
},
}
The location.loc field is 2d indexed. Then I used a geoNear query on mongoDB command
{
"geoNear": "users",
"near": [103.761614, 1.3172431],
"num": 10
}
The result distance returned from mongoDB is 0.004193433515629152 radians which corresponds to more than 20 km. However, these 2 coordinates are just 0.5 km apart. Is there anything I have done wrong? I know it must be some very silly thing, but I just couldn't figure out.
If you want to query related to $geoWithin or $centerSphere or $geoNear location structure like this only:-
"location" : {
"lng" : 77.15319738236303,
"lat" : 28.434568229025803
},
And then run your query. It will give you accurate result.
I have a dataset of ~400k objects in the format:
{
"trip": {
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[
-73.9615,
40.6823
],
[
-73.9704,
40.7849
]
]
},
"properties": {
......
}
}
}
I tried making a 2dsphere index on mLab like so:
{"trip.geometry" : "2dsphere"}
Which I assume just calls:
db.collection.createIndex( {"trip.geometry" : "2dsphere"} )
When I try to do a $geoWithin query like so (about 500 hits):
db.collection.find(
{
"trip.geometry": {
$geoWithin: {
$geometry: {
type : "Polygon" ,
coordinates: [
[
[-74.0345,40.7267],
[-73.9824,40.7174],
[-73.9934,40.7105],
[-74.0345,40.7267]
]
]
}
}
}}
)
I noticed it was very slow, ~2 seconds. I then tried deleting the index entirely, and the time increase was very slight. ~0.5 seconds. Is it possible that this query is not using the index the I had set? I've included the explain() here.
By my interpretation, the winning plan first fetches all the data based on a simple filter, then uses the 2dindex. Shouldn't it start out using the 2dindex, given that the lat and lon data aren't indexed directly?