Related
I have the following object in my Collection:
{
"_id":"test123",
"footprint":{
"type":"Polygon",
"coordinates":[
[
[10, 30], [20, 45], [38, 38], [43, 38], [45, 30], [10, 30]
]
]
}
}
with index of type "2dsphere" on "footprint" attribute.
Now, I would like to implements the geospatial query "overlaps", as implemented by ST_Overlaps in PostGIS: https://postgis.net/docs/ST_Overlaps.html.
Due to the fact that MongoDB doesn't support "overlap" natively (only within, intersect and near) and according to the above definition, I whould return all overlapping documents not totally within the search area.
Using mongo-java-drivers 3.12.8, I developed the following Bson filter:
Polygon polygon = new Polygon(
new PolygonCoordinates(
Arrays.asList(
new Position(41.62109375000001d, 38.087716380862716d),
new Position(41.870727539062514d, 37.998201197578084d),
new Position(41.72393798828124d, 38.01268326428104d),
new Position(41.62109375000001d, 38.087716380862716d)
)
)
);
Bson spatialFilter = Filters.and(
Filters.geoIntersects("footprint", polygon),
Filters.not(Filters.geoWithin("footprint", polygon))
);
But when I execute the following:
db.collection.find(spatialFilter);
I get the following error:
Query failed with error code 2 and error message 'can't parse extra field: $geoWithin: { $geometry: { type: "Polygon", coordinates: [ [ [ 41.62109375000001, 38.08771638086272 ], [ 41.87072753906251, 37.99820119757808 ], [ 41.72393798828124, 38.01268326428104 ], [ 41.62109375000001, 38.08771638086272 ] ] ] } }' on server localhost:27017
As explained here MongoDB can't parse query (2dsphere): two conditions, it seems that the "$and" wrapper filter is not correctly generated.
Am I wrong? Is there any workaround?
Thanks
Maybe, it was a bug in 3.12.8 version.
It seems fixed in 4.2.3 version
I have ~400K documents in a mongo collection, all with geometry of type:Polygon. It is not possible to add a 2dsphere index to the data as it currently stands because the geometry apparently has self-intersections.
In the past we had a hacky workaround which was to compute the bounding box of the geometry on a mongoose save hook and then index that rather than the geometry itself, but we would like to simplify things and just use the actual geometry.
So far I have tried using turf as follows (this is the body of a function called fix):
let geom = turf.polygon(geometry.coordinates);
geom = turf.simplify(geom, { tolerance: 1e-7 });
geom = turf.cleanCoords(geom);
geom = turf.unkinkPolygon(geom);
geom = turf.combine(geom);
return geom.features[0].geometry;
The most important function there is the unkinkPolygons which I hoped would do exactly what I wanted, i.e. make the geometry nice enough to be indexed. The simplify is possibly not helpful but I added it in for good measure. The clean is there because unkink complained about its input, and the combine is there to turn an array of Polygons into a single MultiPolygon. Actually, unkink still wasn't happy with it's inputs, so I had to write a hacky function as follows that jitters duplicated vertices, this modifies the geom before passing to unkink:
function jitterDups(geom) {
let coords = geom.geometry.coordinates;
let points = new Set();
for (let ii = 0; ii < coords.length; ii++) {
// last coords is allowed to match first, not sure if it must match.
let endsMatch = coords[ii][0].join(",") === coords[ii][coords[ii].length - 1].join(",");
for (let jj = 0; jj < coords[ii].length - (endsMatch ? 1 : 0); jj++) {
let str = coords[ii][jj].join(",");
while (points.has(str)) {
coords[ii][jj][0] += 1e-8; // if you make this too small it doesn't do the job
if (jj === 0 && endsMatch) {
coords[ii][coords[ii].length - 1][0] = coords[ii][jj][0];
}
str = coords[ii][jj].join(",");
}
points.add(str);
}
}
}
However, even after all of that mongo still complains.
Here is some sample raw Polygon input:
{ type: "Polygon", coordinates: [ [ [ -0.027542009179339, 51.5122867222457 ], [ -0.027535822940572, 51.512281465421 ], [ -0.027535925691804, 51.5122814221859 ], [ -0.027589474043984, 51.5122605515771 ], [ -0.027638484531731, 51.5122996934574 ], [ -0.027682911101528, 51.5123351881505 ], [ -0.027689915350493, 51.5123872384419 ], [ -0.027672409315982, 51.5123868001613 ], [ -0.027667905522642, 51.5123866344944 ], [ -0.027663068941865, 51.5123864992013 ], [ -0.02764931654289, 51.512375566682 ], [ -0.027552504539425, 51.5122983194123 ], [ -0.027542009179339, 51.5122867222457 ] ], [ [ -0.027542009179339, 51.5122867222457 ], [ -0.027557948301911, 51.5122984109658 ], [ -0.027560309178214, 51.5123001412876 ], [ -0.027542009179339, 51.5122867222457 ] ] ] }
And that same data after it has passed through the above fixing pipeline:
{ type: "MultiPolygon", coordinates: [ [ [ [ -0.027560309178214, 51.5123001412876 ], [ -0.02754202882236209, 51.51228674396312 ], [ -0.027542009179339, 51.5122867222457 ], [ -0.027535822940572, 51.512281465421 ], [ -0.027589474043984, 51.5122605515771 ], [ -0.027682911101528, 51.5123351881505 ], [ -0.027689915350493, 51.5123872384419 ], [ -0.027663068941865, 51.5123864992013 ], [ -0.027552504539425, 51.5122983194123 ], [ -0.02754202884162257, 51.51228674398443 ], [ -0.027557948301911, 51.5122984109658 ], [ -0.027560309178214, 51.5123001412876 ] ] ], [ [ [ -0.02754202884162257, 51.51228674398443 ], [ -0.02754202882236209, 51.51228674396312 ], [ -0.027541999179339, 51.5122867222457 ], [ -0.02754202884162257, 51.51228674398443 ] ] ] ] }
And here is the relevant bit of the error that is spat out by the index creation:
Edges 0 and 9 cross.
Edge locations in degrees: [-0.0275603, 51.5123001]-[-0.0275420, 51.5122867] and [-0.0275420, 51.5122867]-[-0.0275579, 51.5122984]
"code" : 16755,
"codeName" : "Location16755"
My question is: is there a bug in turf, or is it not doing what I need here in terms of keeping mongo happy? Also is there any documentation on exactly what the 2dshpere index needs in terms of "fixing"? Also, does anyone have suggestions as to what other tools I might use to fix the data, e.g. mapshaper or PostGIS's ST_MakeValid.
Note that once the existing data is fixed I also need a solution for fixing new data on the fly (ideally something that works nice with node).
Mongo Version: 3.4.14 (or any later 3.x)
The problem here is not that the polygon is intersecting itself, but rather that you have a (tiny) hole in the polygon, composed of 4 points, which shares a point with the exterior. So the hole "touches" the exterior, not intersects with it, but this is not allowed.
You can fix such cases using Shapely buffer with a tiny value, e.g.:
shp = shapely.geometry.shape({ "type": "Polygon", "coordinates": [ [ [ -0.027542009179339, 51.5122867222457 ], [ -0.027535822940572, 51.512281465421 ], [ -0.027535925691804, 51.5122814221859 ], [ -0.027589474043984, 51.5122605515771 ], [ -0.027638484531731, 51.5122996934574 ], [ -0.027682911101528, 51.5123351881505 ], [ -0.027689915350493, 51.5123872384419 ], [ -0.027672409315982, 51.5123868001613 ], [ -0.027667905522642, 51.5123866344944 ], [ -0.027663068941865, 51.5123864992013 ], [ -0.02764931654289, 51.512375566682 ], [ -0.027552504539425, 51.5122983194123 ], [ -0.027542009179339, 51.5122867222457 ] ], [ [ -0.027542009179339, 51.5122867222457 ], [ -0.027557948301911, 51.5122984109658 ], [ -0.027560309178214, 51.5123001412876 ], [ -0.027542009179339, 51.5122867222457 ] ] ] })
shp = shp.buffer(1e-12, resolution=0)
geojson = shapely.geometry.mapping(shp)
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 am having a lot of trouble with the following Mongo query
location: { $geoWithin: { $centerSphere: [[lon,lat],radians] } }
It only returns geoJSON Points and ignores all my geoJSON Polygons for some reason. The documentation states:
You can use the $centerSphere operator on both GeoJSON objects and legacy coordinate pairs.
I am using Mongoose to run the queries and my geoJSON is coverted from WellKnown Text by the NPM module wellknown. This is how my geoJSON looks after the wellknown module has converted them:
"location": {
"coordinates": [
22.1,
33.3
],
"type": "Point"
}
and
"location": {
"coordinates": [
[
[
43,
30
],
[
40,
28
],
[
49,
27
],
[
43,
30
]
],
[
[
44,
28
],
[
44.7,
28.8
],
[
46,
28
],
[
44,
28
]
]
],
"type": "Polygon"
}
My Mongoose schema is defined as:
location: {
type: schema.Types.Mixed,
index: '2dsphere',
required: false
}
I should add that the withinPolygon methods work as expected and I get both the Points and Polygons returned. The following works completely fine:
location: { $geoWithin: { $geometry: geoJSON } }
Thank you for any help. I have read the documentation and can't see anywhere where it mentions that the $centerSphere only returns geoJSON Points.
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 more information about the update.
Error creating index for table 'MSParcels': WriteConcern detected an error 'Can't extract geo keys from object, malformed geometry?:
{ type: "Polygon", coordinates:
[ [ [ -122.118466012, 47.6511409501, 0.0 ],
[ -122.118687874, 47.6508529655, 0.0 ],
[ -122.118817718, 47.650852731, 0.0 ],
[ -122.118890754, 47.650852592, 0.0 ],
[ -122.118891979, 47.651140118, 0.0 ],
[ -122.118703033, 47.6511404878, 0.0 ],
[ -122.118466012, 47.6511409501, 0.0 ] ] ] }
Problem is, I'm copying from SQL Server where identical coordinates pass STIsValid
Using C# driver MongoDB.Driver.Builders.IndexKeys.GeoSpatialSpherical
Mongo version 2.4.4
Any advice?
The geojson isn't valid for mongodb- it only accepts x,y and not z coordinates (altitude). This is because it only has 2D indexing / querying capabilities.
You need to remove the z coordinates from the geojson document to be something like:
{ type: "Polygon", coordinates:
[ [ [ -122.118466012, 47.6511409501],
[ -122.118687874, 47.6508529655],
[ -122.118817718, 47.650852731],
[ -122.118890754, 47.650852592],
[ -122.118891979, 47.651140118],
[ -122.118703033, 47.6511404878],
[ -122.118466012, 47.6511409501] ] ] }
There has been a feature request to improve this - please vote for: SERVER-9220
Your coordinates invalid. A geojson polygon is a array of arrays of arrays with two coordinates not three (the additional 0.0)