查询匹配包含某点的多边形

5
我的mongodb集合中的文档长这个样子:
{
"_id" : ObjectId("5562d6831683523f449e7d85")
"geometry" : {
"type" : "Polygon",
"coordinates" : 
    [[
    [-122.4,37.81],
    [-132.9, 39.9],
    [-122.28, 37.80],
    [-124.18, 39.81]
    ]]
}}

我有一个点(lat long pair),我将其称为xy。我需要查看文档的坐标是否创建了一个多边形,使得这些坐标位于该多边形内部。
因此,当然我需要计算每条多边形边缘描述的线条等等,然后查看点的坐标是否在其中。但是现在,让我们假设我们只想查询具有xy在整个数组的最大和最小纬度和经度值范围内的文档。
以下是我的查询尝试:
db.<collection-name>.find(
    {'geometry.coordinates':
        {$elemMatch:
            {
                [{$gt:-122.1}, {$lt:-122.0 }], [{$gt: 37.89 },{$lt: 37.91}]
            }
        }
    }
)

然而,结果是:Unexpected token [。我试图按照这里的示例操作。

如果文档中数组的每个元素都有条件,我该如何查询这样的数组?谢谢。


1
我移除了“mysql”标签,因为问题明确涉及MongoDB。 - Gordon Linoff
有更好的方法可以在你的集合中找到一个多边形内的点。然而,你的文档结构(不能有两个名为“type”的键)和坐标映射对于GeoJSON来说是无效的。你把它简化并从文档中删除了一些细节吗?请检查并编辑一个有效的文档。 - Blakes Seven
仍然无效,这就是为什么我正在尝试帮助你。一个“多边形”必须至少包含“四个”点,最后一个点用于闭合循环。此外,正确的符号表示为[[[lon,lat],[lon,lat],[lon,lat],[lon,lat]]],其中双方括号[[每对括起来。如果数据有效,则无需尝试匹配边界内的数组元素。 - Blakes Seven
@BlakesSeven:谢谢。 - makansij
1个回答

10
你似乎正在尝试匹配数组元素,实际上是为了“查找包含点的多边形”,这就是我更改你的问题标题的原因。
为了完成这个任务,你最好使用MongoDB的geoSpatail功能,而不是自己计算边界。对于有效的GeoJSON数据,使用$geoIntersects运算符的查询非常简单。
为了演示,我将首先设置一个带有一些多边形数据的集合:
db.areas.insert([
    {
        "name": "San Jose",
        "geometry": {
            "type": "Polygon",
            "coordinates": [[
                [ -122.20916748046876, 37.13404537126446  ],
                [ -122.20916748046876, 37.496652341233364 ],
                [ -121.65710449218749, 37.496652341233364 ],
                [ -121.65710449218749, 37.13404537126446  ],
                [ -122.20916748046876, 37.13404537126446  ]
             ]]
         }
    },
    {
        "name": "San Franciso",
        "geometry": {
            "type": "Polygon",
            "coordinates": [[
                [ -122.73651123046874, 37.58811876638322 ],
                [ -122.73651123046874, 37.89219554724437 ],
                [ -122.28332519531249, 37.89219554724437 ],
                [ -122.28332519531249, 37.58811876638322 ],
                [ -122.73651123046874, 37.58811876638322 ]
            ]]
        }
    }
])

当处理地理空间数据时(虽然对于$geoIntersects来说并不是必需的),最好定义一个“索引”。对于真正的GeoJSON位置,最合适的是"2dsphere"。索引是在包含GeoJSON数据“根”的字段上创建的,在本例中称为“geometry”:

db.areas.createIndex({ "geometry": "2dsphere" })

然后你所需要做的就是提供一个.find()查询。我在这里使用的是"旧金山市"的坐标:

db.areas.find({
    "geometry": {
        "$geoIntersects": {
             "$geometry": {
                "type": "Point",
                "coordinates": [ 
                    -122.45361328124999, 
                    37.76420119453823
                ]
             }
         }
    }
})

当然,这将返回“Polyon”,定义了“San Franciso”区域,因为该“Point”位于该对象内部。
    {
        "name": "San Franciso",
        "geometry": {
            "type": "Polygon",
            "coordinates": [[
                [ -122.73651123046874, 37.58811876638322 ],
                [ -122.73651123046874, 37.89219554724437 ],
                [ -122.28332519531249, 37.89219554724437 ],
                [ -122.28332519531249, 37.58811876638322 ],
                [ -122.73651123046874, 37.58811876638322 ]
            ]]
        }
    }

这就是在你的集合中查找“点”是否位于你存储的“多边形”内的全部内容。此外,还可以使用工具,如geojsonlint.comgeojson.io(示例,非认可),以验证和可视化数据,从你的示例来看,数据没有提供格式正确的多边形。

好的,太棒了。我不知道这个有内置功能。现在,为什么需要索引呢?对我来说不太清楚。另外,既然MongoDB已经为所有文档使用了_id,为什么还需要索引呢? - makansij
1
@Sother 这个查询并不需要索引,但是迟早你可能会想查询$near,而这需要使用索引。无论如何,在字段(这里是“geometry”)上建立索引总是可以加快搜索速度的。 _id 只是一个“主键”,它不能“辅助”在其他字段上进行搜索。 - Blakes Seven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接