简体   繁体   中英

MongoDB $geowithin not acting as expected

I am storing positions into a collection, and based on a bounding box, I would like to retrieve the positions that are within this bounding box. For small bounding boxes, everything seems to work fine, but for larger bounding boxes, I'm not getting the expected results. I found some information about specifying the CRS when the area of the bounding box is larger than the area of a hemisphere: https://docs.mongodb.com/manual/reference/operator/query/geoWithin/

And although the area of my large bounding box isn't larger than the area of a hemisphere, I don't get any results with the query I was using for a small bounding box.

For a visual representation of my locations and my bounding boxes used below, please refer to the following website and geo-point details:https://mobisoftinfotech.com/tools/plot-multiple-points-on-map/

Small bounding box:

32.441459,-39.891999,blue,marker,""
32.441459,80.332689,blue,marker,""
67.613969,80.332689,blue,marker,""
67.613969,-39.891999,blue,marker,""
50.850189,2.887406,green,marker,"Ypres"
29.780336,-95.359167,red,marker,"Houston"

Big bounding box:

32.441459,-79.891999,blue,marker,""
32.441459,80.332689,blue,marker,""
67.613969,80.332689,blue,marker,""
67.613969,-79.891999,blue,marker,""
50.850189,2.887406,green,marker,"Ypres"
29.780336,-95.359167,red,marker,"Houston"

I'm trying to fetch the data within the bounding box of the blue markers, which should result in the location with the green marker; Ypres.

So in MongoDB, I have these 2 positions:

db.getCollection("positions").insertOne(
{
    "name" : "Ypres, Belgium",
    "pos" : {
        "type" : "Point",
        "coordinates" : [ 
            2.887406, 
            50.850189
        ]
    }
})

db.getCollection("positions").insertOne(
{
    "name" : "Houston, Texas, US",
    "pos" : {
        "type" : "Point",
        "coordinates" : [ 
            -95.359167, 
            29.780336
        ]
    }
})

Small polygon with the coordinates specified in counter-clockwise order; result OK: Ypres

db.getCollection("positions").find({
    "pos": {
        "$geoWithin": {
            "$geometry": {
                "type": "Polygon",
                "coordinates": [[
                    [-39.891999, 32.441459], 
                    [80.332689, 32.441459], 
                    [80.332689, 67.613969], 
                    [-39.891999, 67.613969], 
                    [-39.891999, 32.441459]]]
            }
        }
    }
})

The same small polygon with the coordinates specified in clockwise order; result OK: Ypres

db.getCollection("positions").find({
    "pos": {
        "$geoWithin": {
            "$geometry": {
                "type": "Polygon",
                "coordinates": [[
                    [-39.891999, 32.441459], 
                    [-39.891999, 67.613969], 
                    [80.332689, 67.613969], 
                    [80.332689, 32.441459], 
                    [-39.891999, 32.441459]]]
            }
        }
    }
})

Bigger polygon with the coordinates specified in counter-clockwise order; result not OK; no locations.

db.getCollection("positions").find({
    "pos": {
        "$geoWithin": {
            "$geometry": {
                "type": "Polygon",
                "coordinates": [[
                    [-79.891999, 32.441459], 
                    [80.332689, 32.441459], 
                    [80.332689, 67.613969], 
                    [-79.891999, 67.613969], 
                    [-79.891999, 32.441459]]]
            }
        }
    }
})

So here I think I might need the CRS, but when adding it, I get the same result; no locations.

db.getCollection("positions").find({
    "pos": {
        "$geoWithin": {
            "$geometry": {
                "type": "Polygon",
                "crs": {
                    "type": "name",
                    "properties": {
                        "name": "urn:x-mongodb:crs:strictwinding:EPSG:4326"
                    }
                },
                "coordinates": [[
                    [-79.891999, 32.441459], 
                    [80.332689, 32.441459], 
                    [80.332689, 67.613969], 
                    [-79.891999, 67.613969], 
                    [-79.891999, 32.441459]]]
            }
        }
    }
})

As I'm not entirely sure about the clockwise/counter-clockwise specification when using the CRS, I tried reversing the order of the corners of my polygon. So now in clockwise order. But here I get both locations, while I'm only expecting Ypres.

db.getCollection("positions").find({
    "pos": {
        "$geoWithin": {
            "$geometry": {
                "type": "Polygon",
                "crs": {
                    "type": "name",
                    "properties": {
                        "name": "urn:x-mongodb:crs:strictwinding:EPSG:4326"
                    }
                },
                "coordinates": [[
                    [-79.891999, 32.441459], 
                    [-79.891999, 67.613969], 
                    [80.332689, 67.613969], 
                    [80.332689, 32.441459], 
                    [-79.891999, 32.441459]]]
            }
        }
    }
})

When omitting the CRS, I get no locations for this one.

So, I'm not entirely sure what's going on here. Am I doing something wrong with my queries?

So apparently the $geoWithin operator combined with a Polygon $geometry suffers from 'great circle distance' 'distortion' (not sure how about the correct term, but it's how I understood it) when calculating whether a point is inside the polygon or not. For my purpose and expected result, I had to change my queries to $geoWithin combined with $box instead.

db.getCollection("positions").find({ "pos" : { "$geoWithin" : { "$box" : [[-79.891999, 32.441459], [80.3326890, 67.613969]] } } })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM