Spring Data MongoDB 教程

GeoJSON支持

MongoDB 支持 GeoJSON 和用于地理空间数据的简单(遗留)坐标对。这些格式既可以用于存储数据,也可以用于查询数据。

领域类中的 GeoJSON 类型

在领域类中使用 GeoJSON 类型很简单。org.springframework.data.mongodb.core.geo 包中包含了 GeoJsonPoint、GeoJsonPolygon 等类型。这些类型是现有org.springframework.data.geo 类型的扩展。以下示例展示了 GeoJsonPoint 的应用:

public class Store {

   String id;

   /**
    * location is stored in GeoJSON format.
    * {
    *   "type" : "Point",
    *   "coordinates" : [ x, y ]
    * }
    */
   GeoJsonPoint location;
}

提示:如果一个 GeoJSON 对象的坐标表示纬度和经度对,那么经度在前面,纬度在后。因此,GeoJsonPoint 将 getX() 视为经度,将 getY() 视为纬度。

存储库查询方法中的 GeoJSON 类型

使用 GeoJSON 类型作为存储库的查询参数,在创建查询时必须使用 $geometry 操作符,如下例所示。

public interface StoreRepository extends CrudRepository<Store, String> {
   // 存储库方法的定义使用通用类型,允许用 GeoJSON 和传统格式调用它
   List<Store> findByLocationWithin(Polygon polygon);
}

/*
* {
*   "location": {
*     "$geoWithin": {
*       "$geometry": {
*         "type": "Polygon",
*         "coordinates": [
*           [
*             [-73.992514,40.758934],
*             [-73.961138,40.760348],
*             [-73.991658,40.730006],
*             [-73.992514,40.758934]
*           ]
*         ]
*       }
*     }
*   }
* }
*/
// 使用 GeoJSON 类型可以使用 $geometry运算符
repo.findByLocationWithin(
 new GeoJsonPolygon(
   new Point(-73.992514, 40.758934),
   new Point(-73.961138, 40.760348),
   new Point(-73.991658, 40.730006),
   // 注意,GeoJSON 多边形需要定义一个闭合环,因此第一个和最后一个 point 的坐标一致
   new Point(-73.992514, 40.758934)));

/*
* {
*   "location" : {
*     "$geoWithin" : {
*        "$polygon" : [ [-73.992514,40.758934] , [-73.961138,40.760348] , [-73.991658,40.730006] ]
*     }
*   }
* }
*/
// 使用传统格式 $polygon 运算符
repo.findByLocationWithin(
 new Polygon(
   new Point(-73.992514, 40.758934),
   new Point(-73.961138, 40.760348),
   new Point(-73.991658, 40.730006)));

度量和距离计算

MongoDB 的 $geoNear 操作符允许使用 GeoJSON 点或传统坐标对。

(1)传统坐标对,如下:

NearQuery.near(new Point(-73.99171, 40.738868))

对应的JSON:

{
 "$geoNear": {
   //...
   "near": [-73.99171, 40.738868]
 }
}

(2)GeoJSON 点方式,如下:

NearQuery.near(new GeoJsonPoint(-73.99171, 40.738868))

对应的JSON:

{
 "$geoNear": {
   //...
   "near": { "type": "Point", "coordinates": [-73.99171, 40.738868] }
 }
}

虽然在语法上不同,但无论集合中的目标文档使用什么格式,服务器都能接受这两种格式。

警告:GeoJSON 和传统坐标在距离计算方面有很大的不同。使用传统的格式是在类似地球的球体上操作弧度,而 GeoJSON 格式则使用 Meters。

为了避免严重的麻烦,请确保将 Metric(公制)设置为所需的度量单位,以确保正确计算距离。

换句话说:

假设您有5份文件,如下所示:

{
   "_id" : ObjectId("5c10f3735d38908db52796a5"),
   "name" : "Penn Station",
   "location" : { "type" : "Point", "coordinates" : [  -73.99408, 40.75057 ] }
}
{
   "_id" : ObjectId("5c10f3735d38908db52796a6"),
   "name" : "10gen Office",
   "location" : { "type" : "Point", "coordinates" : [ -73.99171, 40.738868 ] }
}
{
   "_id" : ObjectId("5c10f3735d38908db52796a9"),
   "name" : "City Bakery ",
   "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
}
{
   "_id" : ObjectId("5c10f3735d38908db52796aa"),
   "name" : "Splash Bar",
   "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
}
{
   "_id" : ObjectId("5c10f3735d38908db52796ab"),
   "name" : "Momofuku Milk Bar",
   "location" : { "type" : "Point", "coordinates" : [ -73.985839, 40.731698 ] }
}

使用 GeoJSON 从 [73.99171,40.738868] 获取 400 米半径内的所有文档如下所示:

{
   "$geoNear": {
       "maxDistance": 400, // (1) 距中心点的最大距离,单位为米
       "num": 10,
       "near": { type: "Point", coordinates: [-73.99171, 40.738868] },
       "spherical":true, // (2) GeoJSON 始终在球体上运行,spherical 表示球形的,球状的
       "key": "location",
       "distanceField": "distance"
   }
}

返回以下3份文件:

{
   "_id" : ObjectId("5c10f3735d38908db52796a6"),
   "name" : "10gen Office",
   "location" : { "type" : "Point", "coordinates" : [ -73.99171, 40.738868 ] }
   "distance" : 0.0 // (3) 距中心点的距离,单位为米
}
{
   "_id" : ObjectId("5c10f3735d38908db52796a9"),
   "name" : "City Bakery ",
   "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
   "distance" : 69.3582262492474 // (3) 距中心点的距离,单位为米
}
{
   "_id" : ObjectId("5c10f3735d38908db52796aa"),
   "name" : "Splash Bar",
   "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
   "distance" : 69.3582262492474 // (3) 距中心点的距离,单位为米
}

现在,当使用传统的坐标对时,正如之前讨论的那样,我们对弧度进行操作。所以我们在构建 $geoNear 命令时使用 Metrics#KILOMETERS。Metric 可确保距离乘数被正确设置。

{
   "$geoNear": {
       "maxDistance": 0.0000627142377, // (1) 距中心点的最大距离(弧度)
       "distanceMultiplier": 6378.137, // (2) 距离的乘数,所以我们得到公里作为结果距离
       "num": 10,
       "near": [-73.99171, 40.738868],
       "spherical":true, // (3) 确保对 2d_sphere 索引进行操作
       "key": "location",
       "distanceField": "distance"
   }
}

像 GeoJSON 变体一样返回3个文档:

{
   "_id" : ObjectId("5c10f3735d38908db52796a6"),
   "name" : "10gen Office",
   "location" : { "type" : "Point", "coordinates" : [ -73.99171, 40.738868 ] }
   "distance" : 0.0 // (4) 与中心点的距离,以公里为单位。除以 1000 则匹配 GeoJSON 的单位米
}
{
   "_id" : ObjectId("5c10f3735d38908db52796a9"),
   "name" : "City Bakery ",
   "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
   "distance" : 0.0693586286032982 // (4) 与中心点的距离,以公里为单位。除以 1000 则匹配 GeoJSON 的单位米
}
{
   "_id" : ObjectId("5c10f3735d38908db52796aa"),
   "name" : "Splash Bar",
   "location" : { "type" : "Point", "coordinates" : [ -73.992491, 40.738673 ] }
   "distance" : 0.0693586286032982 // (4) 与中心点的距离,以公里为单位。除以 1000 则匹配 GeoJSON 的单位米
}

GeoJSON Jackson 模块

为了支持 Web,Spring Data 向 ObjectMapper 注册了额外的 Jackson 模块,用于反序列化/序列化常见的 Spring Data 领域类型。

MongoDB 模块还通过 GeoJsonConfiguration 公开 GeoJsonModule 为以下 GeoJSON 类型注册了 Jsondeserializer。

org.springframework.data.mongodb.core.geo.GeoJsonPoint
org.springframework.data.mongodb.core.geo.GeoJsonMultiPoint
org.springframework.data.mongodb.core.geo.GeoJsonLineString
org.springframework.data.mongodb.core.geo.GeoJsonMultiLineString
org.springframework.data.mongodb.core.geo.GeoJsonPolygon
org.springframework.data.mongodb.core.geo.GeoJsonMultiPolygon

注意:

GeoJsonModule 仅注册 JsonDeserializer!

要为 ObjectMapper 配备一组对称的 JsonSerializers,您需要手动为 ObjectMapper 配置这些 JsonSerializers,或者提供一个自定义的 SpringDataJacksonModules 配置,将GeoJsonModule.serializers() 公开为 Spring Bean。

class GeoJsonConfiguration implements SpringDataJacksonModules {

   @Bean
   public Module geoJsonSerializers() {
       return GeoJsonModule.serializers();
   }

}

警告:下一个主要版本(4.0)将同时注册 JsonDeserializers 和 JsonSerializers,默认为 GeoJSON 类型。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号