Assuming I have the following LineString in any document:
{
type: "LineString",
coordinates: [
[ 53.3477, -6.2597 ], [ 51.5008, -0.1224 ],
[48.8567, 2.3508], [52.5166, 13.3833]
]
}
When rendering this line on a map the result is:
How can I get the total distance of this LineString in kilometers, using the mongodb GeoQuery features?
Related
I'm trying to achieve the following behaviour with a mongodb query:
I have documents which have a field location and a 2dshere geospatial index on that field
The documents also have a field maxdistance
The location of the user is available in the variable user.gps as a GeoJSON point
The query currently looks like this:
query["location"] = {
$nearSphere: {
$geometry: user.gps,
$maxDistance: filterDistance
}
};
This query successfully selects all the datasets in a given filterDistance relative to the user.
What i'd like to have now is "If document.maxdistance field > 0 and the distance to the user is greater than document.maxdistance" do not select the dataset.
So i have documents that should not be found if the user lives in a distance greater than a given distance saved inside the document.
I don't know hot to express this in a mongodb query and i couldn't find any example of such a query.
$near/$nearSphere don't support per-document distance. Only per query. The main reason is sorting by distance. If you need only filtering you can use $geoIntersects/$geoWithin, but you will need to change documents to contain a polygon of the covered area, like a circle Pi*2*distance around it's location.
Example:
Assuming you have a document:
{
loc: { type: "Point", coordinates: [ 10, 20 ] },
distance: 10
}
So that it is returned when user's coordinate is within the radius, e.g. [12, 25], and is not returned when user's coordinate is outside, e.g. [12,30].
For that documents should be updated to convert loc/distance pair to a polygon. For the sake of simplicity I'll use octagon, but you may want to increase number of vertices for more accurate results:
{
loc: { type: "Point", coordinates: [ 10, 20 ] },
distance: 10,
area: {
type : "Polygon",
coordinates : [[
[ 17, 27 ],
[ 10, 30 ],
[ 3, 27 ],
[ 0, 20 ],
[ 3, 13 ],
[ 10, 10 ],
[ 17, 13 ],
[ 20, 20 ],
[ 17, 27 ]
]]
}
}
Then you can use $geoIntersects to find documents which area includes user's coordinates:
db.collection.find({
area: {
$geoIntersects: {
$geometry: { type: "Point" , coordinates: [ 12, 25] }
}
}
})
Currently, we are using $centerSphere to find nearby cities. One example is that for the locality Bee Cave in Texas, USA, $centerSphere correctly found the only city Austin in a radius of 30 kilometers (As per documentation, it was converted in radians). Now, for the city Lautoka in Fiji (Lat: -17.6169618, Long: 177.4504609) it is giving the error "Spherical distance would require (unimplemented) wrapping". This is question one: what does this error mean?
We tried implementing the same by using $center. I'm aware we need to give distance in miles rather than radians. After implementing, for Bee Cave, I got US cities that were thousands or hundreds of miles away. One example is Albuquerque. I'm unable to understand why these cities are coming even after following Mongo documentation properly.
I'm using the query (for Bee Cave, TX)
db.places.find{
"geo": {
$geoWithin: { $center: [ [ -97.9524, 30.3061 ] , 18.64 ] }
}
}
$centerSphere can't handle large distances, especially if it has to wrap around the poles, see this JIRA ticket.
Regarding $geoWithin it does not accept the distance in miles, but rather the circle’s radius as measured in the units used by the coordinate system, so latitude and longitude as per the documentation. That results in a very large bounding box that does include Albuquerque
You use $near instead that allows to specify a radius in meters. For example if you use this as your test data:
db.places.insert( {
name: "Bee Cave, Texas",
location: { type: "Point", coordinates: [ -97.9524, 30.3061 ] }
} );
db.places.insert( {
name: "Austin, Texas",
location: { type: "Point", coordinates: [ -97.654724, 30.210768 ] }
} );
db.places.insert( {
name: "Albuquerque",
location: { type: "Point", coordinates: [ -106.621216, 35.113281 ] }
} );
db.places.createIndex( { location: "2dsphere" } )
You can write the following query using the factor 1609.344 to convert miles to meter
db.places.find(
{
location:
{ $near:
{
$geometry: { type: "Point", coordinates: [-97.9524, 30.3061 ] },
$maxDistance: 20*1609.344
}
}
}
)
This query returns both Bee Cave,TX and Austin, TX:
{
"_id":ObjectId("5a7190124f0cd7075d349bbc"),
"name":"Bee Cave, Texas",
"location":{
"type":"Point",
"coordinates":[
-97.9524,
30.3061
]
}
}{
"_id":ObjectId("5a7190124f0cd7075d349bbd"),
"name":"Austin, Texas",
"location":{
"type":"Point",
"coordinates":[
-97.654724,
30.210768
]
}
}
I've been reading through mongo's docs on geospacial querying, and have things working well for singl Polygon types but am having trouble with MultiPolygon. What I want to do is essentially this:
Given a MultiPolygon outlining areas of exclusion:
{
"type" : "MultiPolygon",
"coordinates" : [
[
[
[
-117.873730659485,
33.6152089844919
],
[
-117.873065471649,
33.615048159758
],
[
-117.873044013977,
33.614690770386
],
[
-117.873666286469,
33.6146729008785
],
[
-117.873730659485,
33.6152089844919
]
]
]
]
}
I simply want to be able to pass in a Point to see if it is excluded. I've tried $geoIntersects just to see if it even can determine if a Point is included or not, but that doesn't work. In the end, I want to check that a point is not included within the exclusion list, but the query is simpler without the additional $not operator... Here's what I've been trying:
var geoPoint = {type: 'Point', coordinates: [-117.8731230, 33.6150696]};
db.myCollection.aggregate([
{$match: {'exclusionsPolygons': {$geoIntersects: {$geometry: geoPoint}}}}
]);
Note that if I do the same exact thing with a GeoJSON type of Polygon then it works just fine:
Given this single polygon:
{
"type" : "Polygon",
"coordinates" : [
[
[
-117.8711744,
33.6129677
],
[
-117.8751744,
33.6129677
],
[
-117.874444839148,
33.6162171973226
],
[
-117.87287399259,
33.6172714730352
],
[
-117.871410434393,
33.6165209730032
],
[
-117.8711744,
33.6129677
]
]
]
}
This query works just find and returns the item(s) whose singular polygon contains the point:
var geoPoint = {type: 'Point', coordinates: [-117.8731230, 33.6150696]};
db.myCollection.aggregate([
{$match: {'singularPolygon': {$geoIntersects: {$geometry: geoPoint}}}}
]);
After some tinkering, it turns out the result set was right and I was wrong...
I was using the areas of interest on the map to get addresses to try to query against. One such place was, I thought, in an exclusion polygon:
However, once I made the polygon larger the result set started coming back as I expected it to... So, I reset the polygon and double-checked the map content, finding that if I zoom in further the area of interest was actually excluded from the polygon as there are multiple areas of interest contained:
Whoops - my bad :)
I have a collection called restaurants.. and also i have formatted into geoJSON and I tried to query the following way
db.restaurants.find({ location:
{ $geoWithin:
{ $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })
I have mentioned radius 5/3963.2 (calculation in miles).. but I need radius distance in kilometer like { $centerSphere: [ [ -73.93414657, 40.82302903 ], 5] }
I need to mentioned radius in kilometer
How to do it?
MongoDB expects values in radians.
To convert distance to radians, simply divide the distance value to the radius of the sphere (earth), where:
3963.2 is radius of earth in Miles.
6378.1 is radius of earth in Km.
db.restaurants.find({ location:
{ $geoWithin:
{ $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 6378.1 ] } } })
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