Geospatial queries giving false positives
FerretDB, PostgreSQL, and DocumentDB versions
FerretDB: v2.7.0 PostgreSQL: 17.6 DocumentDB: 0.107.0
Environment
- OS: RHEL 9.5
- Deployment: Docker using ghcr.io/ferretdb/ferretdb:2.7.0
- Deployment details: Docker version 27.5.1
What did you do?
I am noticing different results using $geoIntersects and $near with FerretDB vs MongoDB in the case of very large geometries. The FerretDB behavior appears to be consistent with using postgreSQL/postGIS directly but inconsistent with MongoDB. When running a point-in-polygon query with a very large geometry inserted in the db, the query gives false positives for points that lie outside the geometry.
- Create an index like
{"geometry":"2dsphere"} - Insert a test document where the geometry field contains a very large GeoJson MultiPolygon (example below). Each individual polygon is valid--follows the right-hand rule and does not cross the antimeridian. Taken together, the bounding box for the MultiPolygon is larger than a hemisphere. `"geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -100, -80 ], [ 0, -80 ], [ 0, 80 ], [ -100, 80 ], [ -100, -80 ] ] ], [ [ [ 0, -80 ], [ 100, -80 ], [ 100, 80 ], [ 0, 80 ], [ 0, -80 ] ] ] ]
} `
- Run
$geoIntersects(or$near) queries with test points. Examples:
{"geometry":{"$geoIntersects":{"$geometry":{"type":"Point","coordinates":[179,0]}}}}. This point lies outside the MultiPolygon. MongoDB does not return the document (expected). FerretDB returns the document (unexpected).{"geometry":{"$geoIntersects":{"$geometry":{"type":"Point","coordinates":[-101,-20]}}}}. This point lies outside the MultiPolygon. MongoDB does not return the document (expected). FerretDB returns the document (unexpected).
My current understanding is that the difference has to do with MongoDB using S2 Geometry to represent shapes in a hierarchy of cells when creating its 2dsphere index. On the other hand, postGIS expects the user to subdivide large shapes before indexing using ST_Subdivide or some other method. FerretDB does not provide an interface to functions such as ST_Subdivide and also does not use the S2 method for indexing, which leads to inconsistent behavior with MongoDB unless the user takes actions to reduce the size of geometries. Whether large shapes are subdivided or not also has significant performance consequences.
What did you expect to see?
- Expecting a find filter
{"geometry":{"$geoIntersects":{"$geometry":{"type":"Point","coordinates":[179,0]}}}}not to return the test document. - Expecting a find filter
{"geometry":{"$near":{"$geometry":{"type":"Point","coordinates":[179,0]}},"$maxDistance":0.1}}not to return the test document.
What did you see instead?
- Find filter
{"geometry":{"$geoIntersects":{"$geometry":{"type":"Point","coordinates":[179,0]}}}}returns the test document. - Find filter
{"geometry":{"$near":{"$geometry":{"type":"Point","coordinates":[179,0]}},"$maxDistance":0.1}}returns the test document.
Source: FerretDB/FerretDB