地理空间查询是不是适用于数组? ($geoWithin, $geoIntersects)

Posted

技术标签:

【中文标题】地理空间查询是不是适用于数组? ($geoWithin, $geoIntersects)【英文标题】:Do geospatial queries work on arrays? ( $geoWithin, $geoIntersects )地理空间查询是否适用于数组? ($geoWithin, $geoIntersects) 【发布时间】:2015-12-12 10:29:26 【问题描述】:

我将以下文档存储在 MongoDB 3.0.5 中


    "_id" : ObjectId("55f3a6ae0907233b5e9e7da0"),
    "user" : 
        "id" : "2d5b093ec8a3",
        "regions" : [ 
            
                "id" : NumberLong(1442365443852),
                "name" : "penta",
                "type" : "Polygon",
                "center" : 
                    "lat" : -12.1254159880008100,
                    "lng" : -77.0316830277442930
                ,
                "zoom" : 17.0000000000000000,
                "coordinates" : [ 
                    [ 
                        -77.0322804898023610, 
                        -12.1271067552781560
                    ], 
                    [ 
                        -77.0336792618036270, 
                        -12.1255133434450870
                    ], 
                    [ 
                        -77.0326449349522590, 
                        -12.1239143495252150
                    ], 
                    [ 
                        -77.0300991833209990, 
                        -12.1238251884504540
                    ], 
                    [ 
                        -77.0299865305423740, 
                        -12.1262000752832540
                    ], 
                    [ 
                        -77.0322804898023610, 
                        -12.1271067552781560
                    ]
                ]
            , 
            
                "id" : NumberLong(1442366496200),
                "name" : "triangle",
                "type" : "Polygon",
                "center" : 
                    "lat" : -12.1254749913046230,
                    "lng" : -77.0316598936915400
                ,
                "zoom" : 17.0000000000000000,
                "coordinates" : [ 
                    [ 
                        -77.0313568040728570, 
                        -12.1266573492018090
                    ], 
                    [ 
                        -77.0325788855552670, 
                        -12.1246968022373030
                    ], 
                    [ 
                        -77.0300653204321860, 
                        -12.1246233756874440
                    ], 
                    [ 
                        -77.0313568040728570, 
                        -12.1266573492018090
                    ]
                ]
            
        ]
    

表示存储为多边形的谷歌地图区域数组。我正在尝试用几种替代方法来查询它们,但似乎都没有,所以我想知道地理空间 MongoDB 查询是否适用于数组。

我的 Java 代码是:DBCursor docs = getCollection().find(search);

当几何上我期望匹配时,以下所有 6 个“搜索”查询均不返回任何结果:

"user.regions" : "$geoIntersects" : "$geometry" : "type" : "Polygon" , "coordinates" : [ [ [ -77.02877718955278 , -12.123750122669545] , [ - 77.03457042574883,-12.123750122669545],[-77.03457042574883,-12.12736341792724],[-77.02877718955278,-12.12736341792724],[-77.02877718955278,-12.123750122669545]]]

LI>

"user.regions.0" : "$geoIntersects" : "$geometry" : "type" : "Polygon" , "coordinates" : [ [ [ -77.02877718955278 , -12.123750122669545] , [-77.03457042574883,-12.123750122669545],[-77.03457042574883,-12.12736341792724],[-77.02877718955278,-12.12736341792724],[-77.02877718955278,-12.123750122669545]]]

LI>

"user.regions.0.center" : "$geoIntersects" : "$geometry" : "type" : "Polygon" , "coordinates" : [ [ [ -77.02877718955278 , -12.123750122669545 ],[-77.03457042574883,-12.123750122669545],[-77.03457042574883,-12.12736341792724],[-77.02877718955278,-12.12736341792724],[-77.02877718955278,-12.123750122669545]]]

LI>

"user.regions" : "$geoWithin" : "$geometry" : "type" : "Polygon" , "coordinates" : [ [ [ -77.02877718955278 , -12.123750122669545] , [ - 77.03457042574883,-12.123750122669545],[-77.03457042574883,-12.12736341792724],[-77.02877718955278,-12.12736341792724],[-77.02877718955278,-12.123750122669545]]]

LI>

"user.regions.0" : "$geoWithin" : "$geometry" : "type" : "Polygon" , "coordinates" : [ [ [ -77.02877718955278 , -12.123750122669545] , [-77.03457042574883,-12.123750122669545],[-77.03457042574883,-12.12736341792724],[-77.02877718955278,-12.12736341792724],[-77.02877718955278,-12.123750122669545]]]

LI>

"user.regions.0.center" : "$geoWithin" : "$geometry" : "type" : "Polygon" , "coordinates" : [ [ [ -77.02877718955278 , -12.123750122669545 ],[-77.03457042574883,-12.123750122669545],[-77.03457042574883,-12.12736341792724],[-77.02877718955278,-12.12736341792724],[-77.02877718955278,-12.123750122669545]]]

LI>

我认为我尊重 MongoDB 中的 long/lat 顺序,我在我的多边形中重复结束点,我添加了 type="Polygon" 并且在中心点的情况下它位于 lat/lng 参数下。但没有结果。

我没有创建任何索引,我认为我匹配参数 geoWithin (http://docs.mongodb.org/manual/reference/operator/query/geoWithin/) 和 geoIntercepts (http://docs.mongodb.org/manual/reference/operator/query/geoIntersects/) 的语法


   <location field>: 
      $geoWithin: 
         $geometry: 
            type: <"Polygon" or "MultiPolygon"> ,
            coordinates: [ <coordinates> ]
         
      
   



  <location field>: 
     $geoIntersects: 
        $geometry: 
           type: "<GeoJSON object type>" ,
           coordinates: [ <coordinates> ]
        
     
  

关于“位置字段”,我按照此处所述的数组说明进行操作http://docs.mongodb.org/manual/tutorial/query-documents/

但是没有什么能让查询得到任何结果。我用谷歌搜索了同样的案例,我只能从 2013 年找到这个未解决的问题:How do I perform a find using $geoIntersects / 2dsphere in an array subfield?

所以,除非我犯了一个常见错误,否则我想知道是否可以对数组参数进行地理空间查询?

有什么建议吗?

谢谢

【问题讨论】:

我尝试的另一件事是将我的用例视为此处定义的 GeometryCollection docs.mongodb.org/manual/reference/geojson/…,将 type: "GeometryCollection" 参数添加到我的用户参数并按几何图形更改区域。没有索引。通过使用位置字段 user.geometries 再次查询没有结果。 【参考方案1】:

这是要回答的是和否的问题之一,因为支持数组来匹配结果,但考虑到对如何完成匹配的限制,它也可能不是您真正想要的。

您需要在此处进行的显着更改是对象本身并未以 MongoDB 将识别它们的方式定义为您当前已形成它们。有两种索引和通用查找形式,或者使用旧坐标对(它只是一个 x,y 点),或者使用支持的 GeoJSON 对象作为GeoJSON。您的问题是您的“伪”GeoJSON 格式并不真正符合规范,并且您正在尝试直接访问“坐标”,您需要像这样的***对象:


    "regions": [
        
            "name": "penta",
            "geometry": 
                "type": "Polygon",
                "coordinates": [[
                    [ 
                        -77.0322804898023610, 
                        -12.1271067552781560
                    ], 
                    [ 
                        -77.0336792618036270, 
                        -12.1255133434450870
                    ], 
                    [ 
                        -77.0326449349522590, 
                        -12.1239143495252150
                    ], 
                    [ 
                        -77.0300991833209990, 
                        -12.1238251884504540
                    ], 
                    [ 
                        -77.0299865305423740, 
                        -12.1262000752832540
                    ], 
                    [ 
                        -77.0322804898023610, 
                        -12.1271067552781560
                    ]
                ]]
            
        ,
        
            "name": "triangle",
            "geometry": 
                "type": "Polygon",
                "coordinates": [[
                    [ 
                        -77.0313568040728570, 
                        -12.1266573492018090
                    ], 
                    [ 
                        -77.0325788855552670, 
                        -12.1246968022373030
                    ], 
                    [ 
                        -77.0300653204321860, 
                        -12.1246233756874440
                    ], 
                    [ 
                        -77.0313568040728570, 
                        -12.1266573492018090
                    ]
                ]]
            
        
    ]

这样可以将 GeoJSON 部分抽象为格式良好并与不属于规范的其他元数据分开。理想情况下,您也可以编制索引,尽管 $geoWithin$geoIntersects 不需要,但它肯定会有所帮助:

db.regions.createIndex( "regions.geometry": "2dsphere" )

在数组元素中定义 GeoJSON 定义的完整路径。

然后查询正常工作:

db.regions.find(
    "regions.geometry" :  
        "$geoIntersects" :  
            "$geometry" :  
                "type" : "Polygon" , 
                "coordinates" : [[
                    [ -77.02877718955278 , -12.123750122669545],
                    [ -77.03457042574883 , -12.123750122669545],
                    [ -77.03457042574883 , -12.12736341792724],
                    [ -77.02877718955278 , -12.12736341792724], 
                    [ -77.02877718955278 , -12.123750122669545]
                ]]
            
        
    
)

与上面的文档匹配。但是当然数组中有多个对象,所以问题是,这些对象中的哪一个匹配?没有支持的答案,因为 MongoDB 匹配“文档”并且没有以任何方式指示匹配了哪个数组元素。

聚合$geoNear 中有一个选项允许返回匹配的对象,在这种情况下它将是“最近的”。有了这样的细节,就可以使用该信息来匹配具有完整元数据的哪个数组元素包含为“最近”找到的元素并提取该数据。但同样,它只是“接近”,也永远不会从数组中返回多个结果。

但一般来说,最好将单独的对象作为它们自己的集合中的文档,其中与不同对象的匹配只是匹配文档的问题。因此,使用上面的数组在它自己的集合中,您只需发出匹配几何的查询:

db.shapes.find(
    "geometry" :  
        "$geoIntersects" :  
            "$geometry" :  
                "type" : "Polygon" , 
                "coordinates" : [ [ 
                    [ -77.02877718955278 , -12.123750122669545],
                    [ -77.03457042574883 , -12.123750122669545],
                    [ -77.03457042574883 , -12.12736341792724],
                    [ -77.02877718955278 , -12.12736341792724], 
                    [ -77.02877718955278 , -12.123750122669545]
                ]]
            
        
    
)

这给出了正确的对象,因为在这种情况下,形状与两者相交:


    "_id" : ObjectId("55f8d2fa66c2e7c750414b7a"),
    "name" : "penta",
    "geometry" : 
        "type" : "Polygon",
        "coordinates" : [[
            [
                    -77.03228048980236,
                    -12.127106755278156
            ],
            [
                    -77.03367926180363,
                    -12.125513343445087
            ],
            [
                    -77.03264493495226,
                    -12.123914349525215
            ],
            [
                    -77.030099183321,
                    -12.123825188450454
            ],
            [
                    -77.02998653054237,
                    -12.126200075283254
            ],
            [
                    -77.03228048980236,
                    -12.127106755278156
            ]
        ]]
    


    "_id" : ObjectId("55f8d2fa66c2e7c750414b7b"),
    "name" : "triangle",
    "geometry" : 
        "type" : "Polygon",
        "coordinates" : [[
            [
                    -77.03135680407286,
                    -12.126657349201809
            ],
            [
                    -77.03257888555527,
                    -12.124696802237303
            ],
            [
                    -77.03006532043219,
                    -12.124623375687444
            ],
            [
                    -77.03135680407286,
                    -12.126657349201809
            ]
        ]]
    

所以你可以使用数组,但你只能真正匹配文档,而不是匹配的单个数组成员,所以这当然会返回整个文档,你需要确定哪些成员符合条件在客户端代码中。

另一方面,您的一些查询尝试试图将对象坐标数组“分解”为单个元素。这根本不受支持,因为对象只能作为一个整体来处理,而不是作为它的“点”部分。

【讨论】:

是的,伙计,通过以下 2 个更改,它可以工作:(1) 将区域放置在文档的根部,以及 (2) 使用“regions.geometry”而不是“regions”作为位置字段。几十年来,我可能一直在尝试这些组合。你拯救了我的一天。非常感谢 是的,对不起,这是应得的。我不太习惯在这里发帖。

以上是关于地理空间查询是不是适用于数组? ($geoWithin, $geoIntersects)的主要内容,如果未能解决你的问题,请参考以下文章

这个 mySQL “空间”查询是不是也适用于 SQL Server 2008?

PostgreSQL 是不是实现地理空间关系查询?

iphone 模拟器地理定位功能是不是仅适用于以太网/有线网络连接?

MongoDB中是不是有类似反向地理空间查询的东西?

具有稀疏复合索引的 MongoDB $near 地理空间查询错误 13311

具有稀疏复合索引的 MongoDB $near 地理空间查询错误 13311