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

时间:2015-09-16 01:40:39

标签: mongodb mongodb-query geospatial

我有下面存储在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
                    ]
                ]
            }
        ]
    }
}

表示存储为多边形的Google地图区域数组。我试图用几个替代方案查询它们但似乎没有工作,所以我想知道地理空间的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]]]}}}}

  • {“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]]]}}}}

  • {“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]]]}}}}

  • {“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]]]}}}}

  • {“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]]]}}}}

  • {“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]]]}}}}

我认为我尊重MongoDB中的long / lat顺序,我在我的多边形中重复关闭点,我添加了type =“Polygon”,在中心点的情况下它是在lat / lng params下面。但没有结果。

我没有创建任何索引,我认为我匹配params 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?

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

有什么建议吗?

由于

1 个答案:

答案 0 :(得分:2)

这是肯定的和没有问题要回答的问题之一,因为支持匹配结果的数组,但考虑到匹配方式的限制,它也可能不是你真正想要的。

这里需要进行的显着改变是,对象本身的定义方式不会像MongoDB那样在当前形成它们时识别它们。有两种索引和一般查找形式,可以是传统坐标对(只是一个x,y点),也可以是支持GeoJSON对象的GeoJSON。你的问题是你有一个“psuedo”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
            ]
        ]]
    }
}

所以你可以使用数组,但是你只能匹配文档而不是匹配中的各个数组成员,所以这将返回整个课程文档,你需要确定哪些成员符合标准在客户代码中。

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