MongoDB06 - MongoDB 地理空间

文章目录

  • MongoDB06 - MongoDB 地理空间
    • 一:地理空间数据基础
      • 1:地理数据表示方式
        • 1.1:GeoJSON 格式
        • 1.2:传统坐标对
      • 2:地理空间索引
        • 2.1:2dsphere 索引
        • 2.2:2d索引
        • 2.3:混合索引
    • 二:地理空间查询和聚合
      • 1:完全包含于几何图形
      • 2:与指定几何图形相交
      • 3:找附近点并按距离排序
      • 4:地理空间的聚合操作
      • 5:地理空间计算函数
    • 三:实际应用示例
      • 1:附近地点搜索
      • 2:地理围栏检查
      • 3:多点距离计算
    • 四:Spring Boot Data整合
      • 1:依赖和配置
      • 2:数据模型定义
      • 3:Repository 层
      • 4:服务Service层
      • 5:控制Controller层

一:地理空间数据基础

1:地理数据表示方式

MongoDB 支持两种主要的地理空间数据表示方式: GeoJSON 格式 & 传统坐标对[经度,纬度]

  • 经度在前:GeoJSON 规定坐标顺序为 [经度, 纬度]
  • 有效范围:经度:-180 到 180 & 纬度:-90 到 90
1.1:GeoJSON 格式

GeoJSON支持如下的类型:

Point - 点

{ type: "Point", coordinates: [longitude, latitude] 
}

LineString - 线

{ type: "LineString", coordinates: [[lon1,lat1], [lon2,lat2], ...] 
}

Polygon - 多边形(闭合环)

{ type: "Polygon", coordinates: [[[lon1,lat1], [lon2,lat2], ..., [lon1,lat1]] // 外环// 可以有多个内环(洞)
]}

还有一些不太常用的:MultiPoint、MultiLineString、MultiPolygon、GeometryCollection

1.2:传统坐标对

简单数组格式:[longitude, latitude] -> 仅适用于 2d 索引,不支持复杂几何形状

{loc: [longitude, latitude]
}

2:地理空间索引

2.1:2dsphere 索引

地球球面几何计算,支持所有的 GeoJSON 类型,计算球面距离

支持 $nearSphere、$geoWithin、$geoIntersects 等操作

db.collection.createIndex({ <locationField>: "2dsphere" } // 创建索引
)
2.2:2d索引

平面几何计算,仅支持点数据(坐标对),计算平面距离(不考虑地球曲率)。·性能更高但精度较低

db.collection.createIndex({ <locationField>: "2d" }
)
2.3:混合索引

可以组合地理空间索引与其他字段:

db.places.createIndex({ location: "2dsphere", name: 1 }
)

二:地理空间查询和聚合

1:完全包含于几何图形

$geoWithin -> 查找完全包含在指定几何图形内的文档

  • 使用 GeoJSON:$geometry
  • 使用传统坐标:$box$polygon$center$centerSphere
db.places.find({location: {$geoWithin: {// 返回在如下多边形中的文档$geometry: {type: "Polygon",coordinates: [[ [0,0], [3,6], [6,1], [0,0] ]}}}
})

2:与指定几何图形相交

$geoIntersects -> 查找与指定几何图形相交的文档

db.places.find({location: {$geoIntersects: {// 返回和这条线相交的文档$geometry: {type: "LineString",coordinates: [[0,0], [5,5]]}}}
})

3:找附近点并按距离排序

$near -> 找附近点并按距离排序

db.places.find({location: {$near: {// 找到举例给定中心点附近的点,最小距离100m,最大距离500m$geometry: {type: "Point",coordinates: [-73.9667, 40.78]},$maxDistance: 500,  // 米(2dsphere)$minDistance: 100}}
})

4:地理空间的聚合操作

使用$geoNear是基于距离的管道聚合,对于$geoNear有如下的说明:

  • 必须是管道的第一阶段
  • 自动按距离排序
  • 可返回计算的距离值
db.places.aggregate([{$geoNear: {// near:参考点// distanceField:存储距离的字段// maxDistance/minDistance:距离范围// spherical:是否使用球面计算// query:附加查询条件// $geoWithin 可在聚合中使用// 结合 $project 计算自定义地理空间数据near: { type: "Point", coordinates: [-73.9667, 40.78] },distanceField: "distance",maxDistance: 2000,spherical: true,query: { category: "Park" }}}
])

5:地理空间计算函数

$geoDistance:计算两点间距离

{$project: {distance: {$geoDistance: {// 起点是文档中的location字段start: "$location",// 终点是GeoJson的坐标点end: { type: "Point", coordinates: [-73.98, 40.77] },distanceMultiplier: 0.001 // 转换为公里}}}
}

三:实际应用示例

1:附近地点搜索

db.places.find({location: {$nearSphere: {// 在给定点1km之内的文档$geometry: {type: "Point",coordinates: [currentLng, currentLat]},$maxDistance: 1000 // 1公里内}},category: "restaurant"
}).limit(20)

2:地理围栏检查

// 检查点是否在配送区域内
db.deliveryZones.find({area: {$geoIntersects: {$geometry: {type: "Point",coordinates: [orderLng, orderLat]}}}
})

3:多点距离计算

db.stores.aggregate([{$geoNear: {// 指定参考点near: { type: "Point", coordinates: [userLng, userLat] },// 指定输出字段名,用于存储计算的距离值distanceField: "distance",// 使用球面spherical: true}},// 结果过滤,只要5km内的{ $match: { distance: { $lte: 5000 } } }, // 5公里内// 按照距离正序排序{ $sort: { distance: 1 } }
])

四:Spring Boot Data整合

1:依赖和配置

<dependencies><!-- Spring Boot Starter Data MongoDB --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency><!-- 其他必要依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Lombok (可选) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>
# application.properties
spring:data:mongodb:host: localhostport: 27017database: geo_db

2:数据模型定义

创建地理空间实体

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Data;@Data
@Document(collection = "places")
public class Place {@Idprivate String id;private String name;private String category;private GeoJsonPoint location;  // 使用GeoJsonPoint存储地理坐标// 构造方法、getter/setter等// Lombok的@Data注解会自动生成这些
}

地理空间索引配置

import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;@Configuration
public class MongoConfig {// 添加监听器@Beanpublic BeforeConvertListener beforeConvertListener() {return new BeforeConvertListener();}// 定义监听器,继承地理事件监听器public static class BeforeConvertListener extends AbstractMongoEventListener<Place> {@Overridepublic void onBeforeConvert(BeforeConvertEvent<Place> event) {// 说明要进行索引操作了IndexOperations indexOps = event.getCollection().getIndexOperations();// 定义索引// 确保location字段有2dsphere索引IndexDefinition indexDef = new GeoSpatialIndexDefinition("location").typed(GeoSpatialIndexType.GEO_2DSPHERE);// 添加索引indexOps.ensureIndex(indexDef);}}
}

3:Repository 层

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.repository.Query;
import java.util.List;public interface PlaceRepository extends MongoRepository<Place, String> {// 查找附近的点(按距离排序)List<Place> findByLocationNear(Point point, Distance distance);// 查找指定类别附近的点List<Place> findByCategoryAndLocationNear(String category, Point point, Distance distance);// 使用GeoJSON多边形查询@Query("{ 'location' : { $geoWithin : { $geometry : { type : 'Polygon', coordinates : ?0 } } }")List<Place> findWithinPolygon(List<List<Double[]>> polygonCoordinates);// 查找与指定线相交的地点@Query("{ 'location' : { $geoIntersects : { $geometry : { type : 'LineString', coordinates : ?0 } } }")List<Place> findIntersectingLine(List<Double[]> lineCoordinates);// 如果是聚合查询@Aggregation(pipeline = {"{ $geoNear: { " +"  near: { type: 'Point', coordinates: [ ?0, ?1 ] }, " +"  distanceField: 'distance', " +"  maxDistance: ?2, " +"  spherical: true " +"} }","{ $match: { category: ?3 } }","{ $sort: { distance: 1 } }","{ $limit: ?4 }"})List<Place> findNearbyPlacesWithAggregation(double longitude, double latitude, double maxDistanceInMeters,String category,int limit);
}

4:服务Service层

import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class GeoService {private final PlaceRepository placeRepository;public GeoService(PlaceRepository placeRepository) {this.placeRepository = placeRepository;}/*** 查找附近的地点* @param longitude 经度* @param latitude 纬度* @param distance 距离(公里)* @return 附近的地点列表*/public List<Place> findNearbyPlaces(double longitude, double latitude, double distance) {Point point = new Point(longitude, latitude);Distance radius = new Distance(distance, Metrics.KILOMETERS);return placeRepository.findByLocationNear(point, radius);}/*** 查找特定类别附近的地点*/public List<Place> findNearbyPlacesByCategory(double longitude, double latitude, double distance, String category) {Point point = new Point(longitude, latitude);Distance radius = new Distance(distance, Metrics.KILOMETERS);return placeRepository.findByCategoryAndLocationNear(category, point, radius);}/*** 多边形区域查询*/public List<Place> findWithinPolygon(List<List<Double[]>> polygonCoordinates) {return placeRepository.findWithinPolygon(polygonCoordinates);}/*** 与线相交的地点查询*/public List<Place> findIntersectingLine(List<Double[]> lineCoordinates) {return placeRepository.findIntersectingLine(lineCoordinates);}// 使用 GeoJson 对象public List<Place> findWithinGeoJsonPolygon(GeoJsonPolygon polygon) {return mongoTemplate.find(Query.query(Criteria.where("location").within(polygon)), Place.class);
}

5:控制Controller层

import org.springframework.web.bind.annotation.*;
import org.springframework.data.geo.Point;
import java.util.List;@RestController
@RequestMapping("/api/places")
public class PlaceController {private final GeoService geoService;public PlaceController(GeoService geoService) {this.geoService = geoService;}@GetMapping("/nearby")public List<Place> getNearbyPlaces(@RequestParam double longitude,@RequestParam double latitude,@RequestParam(defaultValue = "5") double distance) {return geoService.findNearbyPlaces(longitude, latitude, distance);}@GetMapping("/nearby/{category}")public List<Place> getNearbyPlacesByCategory(@PathVariable String category,@RequestParam double longitude,@RequestParam double latitude,@RequestParam(defaultValue = "5") double distance) {return geoService.findNearbyPlacesByCategory(longitude, latitude, distance, category);}@PostMapping("/within-polygon")public List<Place> getPlacesWithinPolygon(@RequestBody List<List<Double[]>> polygonCoordinates) {return geoService.findWithinPolygon(polygonCoordinates);}@PostMapping("/intersecting-line")public List<Place> getPlacesIntersectingLine(@RequestBody List<Double[]> lineCoordinates) {return geoService.findIntersectingLine(lineCoordinates);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/86763.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/86763.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/86763.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Bugku——WEB篇(持续更新ing)

目录 一、滑稽 二、计算器 方法一 方法二 三、alert 四、你必须让他停下 五、头等舱 六、GET 七、POST 方法一 方法二 八、source 九、矛盾 十、备份是个好习惯 一、滑稽 1.启动环境后&#xff0c;访问URL&#xff0c;页面出现了一堆滑稽表情 2.按f12(或fnf12)打…

Linux 网络命名空间的奥秘:深入解析struct net与内核模块编译陷阱

引言:网络隔离的基石 在Linux容器化技术(如Docker)和云计算网络中,网络命名空间是实现网络隔离的核心机制。每个隔离的网络环境都由一个关键的内核数据结构描述——struct net。这个结构体不仅是网络隔离的技术基础,也是内核开发者常遇到的编译陷阱源头。 一、解剖网络命…

idea的EasyCode插件连接瀚高数据库(APP)

文章目录 环境症状问题原因解决方案 环境 系统平台&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;5.6.5 症状 客户在idea工具中使用EasyCode插件连接瀚高数据库的企业版时&#xff0c;连接设置的url中提示“jdbc:highgo不存在”的错误 问题原因 E…

VMware设置虚拟机为固定IP

1. 修改虚拟网络编辑器 打开虚拟机网络“编辑” 点击“VMnet8” 选择“NAT”模式 修改网关&#xff1a;前面的不要修改&#xff0c;最后一位设置为“1”&#xff0c;然后确定 记住这里的网关&#xff0c;后面的配置要保持一致 设置子网IP和子网掩码&#xff1a;一般就…

智核引擎融合生成式AI,重塑企业知识图谱与研发创新范式!

目录 系统架构设计核心实现步骤步骤1&#xff1a;知识图谱构建与数据预处理步骤2&#xff1a;生成式AI与知识图谱融合&#xff08;RAG增强&#xff09;步骤3&#xff1a;智能推理工作流 核心流程可视化企业级部署方案性能优化策略应用场景示例结语 本文将手把手实现企业级知识图…

LogisticRegression(solver = ‘lbfgs‘)的ConvergenceWarning问题解决

&#x1f466;&#x1f466;一个帅气的boy&#xff0c;你可以叫我Love And Program &#x1f5b1; ⌨个人主页&#xff1a;Love And Program的个人主页 &#x1f496;&#x1f496;如果对你有帮助的话希望三连&#x1f4a8;&#x1f4a8;支持一下博主 LogisticRegression的Co…

web3 docs

区块链重构信任机制&#xff0c;去中心化&#xff0c;用唯一的hash编号来实现防篡改。以数字货币的形式交易&#xff0c;个人持有唯一的数字秘钥(唯一&#xff0c;不可篡改) 详见 以太坊的白皮书 和 数字货币 (加密货币实现隐私交易) 底层基础的很多特点 1.例如p2p&#xf…

AI入门 | 计算自注意力时QK^T的计算复杂度是多少?

0. 背景 假设我们有两个矩阵&#xff1a; 矩阵 A&#xff0c;尺寸为 (n, d_k)矩阵 B&#xff0c;尺寸为 (d_k, n) 我们要计算它们的乘积 C A * B。 那么这个过程所需的计算量是多少&#xff1f; 1. 结果矩阵的尺寸 首先&#xff0c;结果矩阵 C 的尺寸是由第一个矩阵的行数…

NeRF-Lidar实景重建:大疆Mavic 4 Pro低成本建模方案(2025实战指南)

摘要 面对传统激光雷达建模​​成本高昂​​&#xff08;单设备超$20万&#xff09;与​​操作复杂​​的行业痛点&#xff0c;本文提出基于消费级无人机大疆Mavic 4 Pro的​​NeRF-LiDAR融合重建方案​​&#xff0c;实现厘米级精度建模成本降低至1/10。核心技术突破在于&…

x64dbg设置条件断点

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、x64是什么?二、条件断点1.CreateWindowExW函数设置当窗口名称为xxx字符串时候break总结前言 提示:这里可以添加本文要记录的大概内容: x64dbg设置条件断点 版本 2024 mar 27 提示:以…

RNN人名分类器案例

RNN人名分类器案例 1 任务目的&#xff1a; 目的: 给定一个人名&#xff0c;来判定这个人名属于哪个国家 典型的文本分类任务: 18分类---多分类任务 2 数据格式 注意&#xff1a;两列数据&#xff0c;第一列是人名&#xff0c;第二列是国家类别&#xff0c;中间用制表符号&q…

鸿蒙HarmonyOS 关于图片、视频的选择详解

背景 在聊天软件中&#xff0c;发送相册中视频和照片、用相机拍摄视频和图片发送是很常用的功能。在Android和iOS端&#xff0c;大部分应用都通过API方式定义UI来实现相册选择照片、视频&#xff0c;相机拍摄照片、视频&#xff0c;它们一般都支持以下功能&#xff1a; 相册选…

iOS 网络请求断连重试失败?抓包分析丢包原因的完整流程

在移动 App 的开发中&#xff0c;中断网络环境&#xff08;如切换到飞行模式再回网&#xff09;后&#xff0c;App 在重连过程中有时会出现请求未重新发送或丢包的情况。这类问题难重现、难定位&#xff0c;尤其在 iOS 平台上更容易被忽视。我们最近就遇到一个用户反馈“切换网…

使用 DHTMLX Gantt 添加迷你地图:提升大型项目可视化与导航体验

在应对数千个任务构成的大型项目时&#xff0c;DHTMLX Gantt 以其卓越的性能表现和流畅渲染能力广受欢迎。然而&#xff0c;在实际使用中&#xff0c;终端用户往往需要快速定位到时间线中的特定位置&#xff0c;这在面对庞杂任务结构时尤为困难。为此&#xff0c;DHTMLX 提供了…

ROM修改进阶教程------用于自启脚本来打开系统的一些常用开关等指令 备份收藏 【一】

在定制化rom中。有很多项目需要反编译系统的相关应用来实现。但有些功能项完全可以使用指令来更改。那么结合自启脚本就可以很方便的来实现很多功能。网络虽然有很多类似的指令,但一些相关定制化项目的指令很少见而且不全面。此博文将全面收录此类指令。方便rom修改用户借鉴参…

腾讯云TSE注册中心实战:Nacos高可用集群搭建与流量治理避坑指南

1. 为什么选择腾讯云TSE托管Nacos&#xff1f; 在微服务架构中&#xff0c;注册中心承担着服务发现与配置管理的核心职能。Nacos作为阿里开源的动态服务发现组件&#xff0c;已成为国内微服务生态的事实标准。腾讯云微服务引擎TSE&#xff08;Tencent Cloud Service Engine&am…

领域驱动设计(DDD)【26】之CQRS模式初探

文章目录 一 CQRS初探&#xff1a;理解基本概念1.1 什么是CQRS&#xff1f;1.2 CQRS与CRUD的对比1.3 为什么需要CQRS&#xff1f; 二 CQRS深入&#xff1a;架构细节2.1 基本架构组成2.2 数据流示意图 三 CQRS实战&#xff1a;电商订单案例3.1 传统CRUD方式的订单处理3.2 CQRS方…

项目测试-接口测试

软件测试的分类 软件测试主要分硬件和软件 硬件测试: cpu,内存条,显卡...测试可以看得见摸得着的东西 软件测试: web,app,小程序... 测试可以看得见摸不着的东西 web端 web端是在电脑上常常使用的, 也可以称之为网站.(web端是B/S架构) web端的客户端是任何一个访问这个网…

相机的光圈

光圈&#xff08;Aperture&#xff09;是镜头中一个控制光线进入相机的开口&#xff0c;它在摄影中起着至关重要的作用。光圈的大小决定了进入相机传感器的光线数量&#xff0c;并影响曝光、景深、以及拍摄效果。光圈参数通常用f/值&#xff08;光圈值&#xff09;来表示&#…

HarmonyOS NEXT仓颉开发语言实战案例:小而美的旅行App

大家周末好&#xff0c;本文分享一个小而美的旅行app首页&#xff0c;效果图如下&#xff1a; 很显然这个页面还是使用List容器&#xff0c;页面两侧有统一的边距&#xff0c;我们可以在List容器统一设置&#xff1a; List(space:20){ } .padding(left:14,right:14,top:62) .w…