基于MongoDB的空间数据存储与查询
一、概念说明
1.1 空间地理数据
MongoDB 中使用 GeoJSON对象 或 坐标对 描述空间地理数据。MongoDB使用 WGS84 参考系进行地理空间数据查询。
1、MongoDB支持空间数据的存储,数据类型需要限制为GeoJSON;
2、MongoDB可以为GeoJSON类型数据建立索引,提升空间查询的效率;
1.2 GeoJSON对象
GeoJSON 对象格式
<field>: { type: <GeoJSON type> , coordinates: <coordinates> }
GeoJSON 对象有两个filed,分别是 type 和 coordinates.其中,
-
type 指明是哪种空间地理数据类型
-
coordinates: 是描述 Geo对象的坐标数组,经度在前(经度取值范围 -180到 180),纬度在后(纬度取值范围是-90到90
二、功能演示操作
2.1 准备环境与初始数据
2.1.1、使用SpringBoot 和 MongoTemplate操作
增加MongoDB连接配置
spring:data:# MongoDB配置mongodb:uri: mongodb://usr:usrpassword@192.168.xx.xx:27017/database: filedataauthentication-database: admin#自动创建索引auto-index-creation: trueconnections-num-min-size: 5connections-num-max-size: 10
2.1.2、创建GeoData对象存储空间数据
@Data
@ApiModel
@Document(collection = "GEO-DATA")
public class GeoData {@ApiModelProperty(name = "_id",value = "_id")private String _id;@ApiModelProperty(name = "recordId",value = "recordId")private String recordId;@ApiModelProperty(name = "name",value = "名称")private String name;/** 经度 */@ApiModelProperty(name = "lng",value = "经度")private Double lng;/** 维度 */@ApiModelProperty(name = "lat",value = "维度")private Double lat;/*** 位置信息*/@ApiModelProperty(name = "location",value = "位置信息", hidden = true)private GeoJsonPoint location;@ApiModelProperty(name = "time",value = "录入时间")private Long time;
}
2.1.3、增加集合GEO-DATA并创建对应的空间索引
db.getCollection("GEO-DATA").ensureIndex( { location :"2dsphere" } )
2.1.4、创建测试类MongoGeoTest
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MongoGeoTest {@Autowiredprivate MongoTemplate mongoTemplate;}
2.1.5、增加批量插入数据的方法
/*** 批量插入数据*/
public void batchInsertData() {//准备数据List<GeoData> geoDataList = new ArrayList<>();for (int i = 0; i < 10; i++) {GeoData geoData = new GeoData();geoData.setRecordId(UUID.fastUUID().toString(Boolean.TRUE));geoData.setName(RandomUtil.randomNumbers(12));geoData.setTime(new Date().getTime());//经度double lng = 116.3180D + RandomUtil.randomDouble(0.1d, 1.0d);geoData.setLng(lng);//维度double lat = 39.9857D + RandomUtil.randomDouble(0.1d, 1.0d);geoData.setLat(lat);geoData.setLocation(new GeoJsonPoint(lng, lat));geoDataList.add(geoData);}//保存数据Long start = System.currentTimeMillis();mongoTemplate.insert(geoDataList, "GEO-DATA");log.info("Mongo save documents to GEO-DATA 耗时:{} 毫秒", System.currentTimeMillis() - start);
}
2.2 多边形区域内查询
2.2.1、创建查询参数类MultiPositionPageQueryParam
@Data
@ApiModel
public class MultiPositionPageQueryParam {@ApiModelProperty(name = "positions",value = "位置集合")private List<BDSPosition> positions;@ApiModelProperty(name = "geoType", value = "类型: 1-多点(位置)查询;2-面(区域)查询")private Integer geoType;@NotNull@ApiModelProperty(name = "pageNum",value = "pageNum 起始数字为 0")private Long pageNum;@NotNull@ApiModelProperty(name = "pageSize",value = "pageSize")private Long pageSize;@ApiModelProperty(name = "needCount",value = "是否需要统计总记录数")private Boolean needCount = Boolean.FALSE;
}
2.2.2、增加多边形区域查询方法
/*** 多边形区域内** @param queryParam*/
public void queryGeoDataByMultiPositionPageQueryParam(MultiPositionPageQueryParam queryParam) {Query query = new Query();Criteria criteria = new Criteria();List<Criteria> criteriaList = new LinkedList<>();//过滤字段query.fields().include("recordId", "_id", "name", "time", "lng", "lat", "location");//位置集合过滤if (ObjectUtil.isNotNull(queryParam.getPositions()) && queryParam.getPositions().size() > 0) {// 类型: 1-多点(位置)查询;2-面(区域)查询if (ObjectUtil.isNotNull(queryParam.getGeoType()) && queryParam.getGeoType() == 2 && queryParam.getPositions().size() > 2) {List<Point> pointList = new LinkedList<>();//经纬度获取for (BDSPosition position : queryParam.getPositions()) {Point point = new Point(position.getLng(), position.getLat());pointList.add(point);}pointList.add(pointList.get(0));GeoJsonPolygon geoJsonPolygon = new GeoJsonPolygon(pointList);Criteria areaCriteria = Criteria.where("location").within(geoJsonPolygon);query.addCriteria(areaCriteria);criteriaList.add(areaCriteria);} else {List<Criteria> orCriteriaList = new LinkedList<>();//经纬度判断for (BDSPosition position : queryParam.getPositions()) {orCriteriaList.add(Criteria.where("lng").is(position.getLng()).and("lat").is(position.getLat()));}Criteria orPositionCriteria = new Criteria().orOperator(orCriteriaList);query.addCriteria(orPositionCriteria);criteriaList.add(orPositionCriteria);}}//总记录数统计Long total = null;if (queryParam.getNeedCount()) {total = mongoTemplate.findDistinct(query, "recordId", "GEO-DATA", String.class).stream().count();}//排序List<Sort.Order> orders = new LinkedList<>();orders.add(Sort.Order.desc("time"));AggregationOptions aggregationOptions = AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build();Aggregation aggregation = null;if (criteriaList.size() > 0) {criteria = criteria.andOperator(criteriaList);aggregation = Aggregation.newAggregation(Aggregation.project("recordId", "_id", "name", "time", "lng", "lat", "location"),//查询条件Aggregation.match(criteria),//分组条件Aggregation.group("recordId").max("time").as("time").first("recordId").as("recordId").last("time").as("time"),Aggregation.sort(Sort.by(orders)),//分页条件Aggregation.skip(queryParam.getPageNum()),Aggregation.limit(queryParam.getPageSize())).withOptions(aggregationOptions);} else {aggregation = Aggregation.newAggregation(Aggregation.project("recordId", "_id", "name", "time", "lng", "lat", "location"),//分组条件Aggregation.group("recordId").max("time").as("time").first("recordId").as("recordId").first("time").as("time"),Aggregation.sort(Sort.by(orders)),//分页条件Aggregation.skip(queryParam.getPageNum()),Aggregation.limit(queryParam.getPageSize())).withOptions(aggregationOptions);}List<GeoData> list = mongoTemplate.aggregate(aggregation, "GEO-DATA", GeoData.class).getMappedResults();log.info("Data: {}", list);
}
2.3 圆形区域内查询
2.3.1、创建查询参数类CirclePageQueryParam
@Data
@ApiModel
public class CirclePageQueryParam {@NotNull@ApiModelProperty(name = "lng", value = "经度")private Double lng;@NotNull@ApiModelProperty(name = "lat", value = "维度")private Double lat;@NotNull@ApiModelProperty(name = "radius", value = "半径")private Double radius;@NotNull@ApiModelProperty(name = "pageNum",value = "pageNum 起始数字为 0")private Long pageNum;@NotNull@ApiModelProperty(name = "pageSize",value = "pageSize")private Long pageSize;@ApiModelProperty(name = "needCount",value = "是否需要统计总记录数")private Boolean needCount = Boolean.FALSE;
}
2.3.2、增加圆形区域查询方法
/*** 圆形区域内查询* @param queryParam*/
public void queryGeoDataByCircle(CirclePageQueryParam queryParam) {Query query = new Query();Criteria criteria = new Criteria();List<Criteria> criteriaList = new LinkedList<>();//过滤字段query.fields().include("recordId", "_id", "name", "time", "lng", "lat", "location");//位置集合过滤if (ObjectUtil.isNotNull(queryParam.getLat()) && ObjectUtil.isNotNull(queryParam.getLng())&& ObjectUtil.isNotNull(queryParam.getRadius())) {Point point = new Point(queryParam.getLng(), queryParam.getLat());Distance distance = new Distance(queryParam.getRadius(), Metrics.MILES);Circle circle = new Circle(point, distance);Criteria areaCriteria = Criteria.where("location").withinSphere(circle);query.addCriteria(areaCriteria);criteriaList.add(areaCriteria);}else{log.info("参数有误,必要参数为空。");return;}//总记录数统计Long total = null;if (queryParam.getNeedCount()) {total = mongoTemplate.findDistinct(query, "recordId", "GEO-DATA", String.class).stream().count();}//排序List<Sort.Order> orders = new LinkedList<>();orders.add(Sort.Order.desc("time"));AggregationOptions aggregationOptions = AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build();Aggregation aggregation = null;if (criteriaList.size() > 0) {criteria = criteria.andOperator(criteriaList);aggregation = Aggregation.newAggregation(Aggregation.project("recordId", "_id", "name", "time", "lng", "lat", "location"),//查询条件Aggregation.match(criteria),//分组条件Aggregation.group("recordId").max("time").as("time").first("recordId").as("recordId").last("time").as("time"),Aggregation.sort(Sort.by(orders)),//分页条件Aggregation.skip(queryParam.getPageNum()),Aggregation.limit(queryParam.getPageSize())).withOptions(aggregationOptions);} else {aggregation = Aggregation.newAggregation(Aggregation.project("recordId", "_id", "name", "time", "lng", "lat", "location"),//分组条件Aggregation.group("recordId").max("time").as("time").first("recordId").as("recordId").first("time").as("time"),Aggregation.sort(Sort.by(orders)),//分页条件Aggregation.skip(queryParam.getPageNum()),Aggregation.limit(queryParam.getPageSize())).withOptions(aggregationOptions);}List<GeoData> list = mongoTemplate.aggregate(aggregation, "GEO-DATA", GeoData.class).getMappedResults();log.info("Data: {}", list);
}
相关文章:
基于MongoDB的空间数据存储与查询
一、概念说明 1.1 空间地理数据 MongoDB 中使用 GeoJSON对象 或 坐标对 描述空间地理数据。MongoDB使用 WGS84 参考系进行地理空间数据查询。 1、MongoDB支持空间数据的存储,数据类型需要限制为GeoJSON; 2、MongoDB可以为GeoJSON类型数据建立索引,提升空…...
jquery中pdf的上传、下载及excel导出
jquery中pdf的上传、下载及excel导出 1.PDF上传 pdfUpload2. pdf下载和excel导出用的一种方法,并且需要引入utils.js2.1PDF下载 pdfDownload2.2导出Excel excelExport 1.PDF上传 pdfUpload //PDF上传 pdfUpload window.pdfUploadfunction (obj){layer.open({type:…...
【MyBatis】:PageHelper分页插件与特殊字符处理
目录 一、PageHelper介绍 二、PageHelper使用 1. 导入pom依赖 2. Mybatis.cfg.xml 配置拦截器 3. 配置 Mapper.xml 4. 编写测试 三、特殊字符处理 1. 使用转义字符 2. 使用CDATA 区段 一、PageHelper介绍 PageHelper 是 Mybatis 的一个插件,这里就不扯了&a…...
C语言练习1(巩固提升)
C语言练习1 选择题 前言 “人生在勤,勤则不匮。”幸福不会从天降,美好生活靠劳动创造。全面建成小康社会的奋斗目标,为广大劳动群众指明了光明的未来;全面建成小康社会的历史任务,为广大劳动群众赋予了光荣的使命&…...
eCharts热力图Y轴左上角少一块
问题: 如图 在图例的左上角 Y轴会少一块 官方demo https://echarts.apache.org/examples/zh/editor.html?cheatmap-cartesian 事实上 把官方demo的左上角坐标 [ 6, 0, 1 ] 修改为 [ 6, 0, 0 ] 后 依旧会出现该问题 查遍文档 并无解释 也没有任何配置项可解决…...
RabbitMQ介绍
RabbitMQ的概念 RabbitMQ 是一个消息中间件:它接受并转发消息。你可以把它当做一个快递站点,当你要发送一个包裹时,你把你的包裹放到快递站,快递员最终会把你的快递送到收件人那里,按照这种逻辑 RabbitMQ 是 一个快递…...
玩转软件|钉钉个人版内测启动:AI探索未来的工作方式
目录 前言 正文 AI为核心,个人效率为王! 指令中心,解锁AI技巧! 灵感Store,探索更多可能! 未来的AI,即将问世! 个人内测体验 前言 重磅消息:钉钉个人版在8月16日正…...
【Linux】一张图了解系统文件
首先先认识磁盘结构 系统文件分布图 文件查找 文件删除 文件的增删改查都是围绕inode来完成的,所以当我们要进行文件删除的时候,只需要通过inode来获取到它对应的block bitmap和inode bitmap数据块容器和保存文件属性的位置置为 0即可 ,如果想…...
自动化测试平台seldom-platform部署及使用
介绍 seldom-platform是一个基于seldom测试框架的测试平台 项目地址:https://github.com/SeldomQA 文档:seldom 语雀 首先,专门为seldom测试框架提供平台化支持。其次,只负责自动化测试项目的解析、执行用例,当然…...
2023年8月第3周大模型荟萃
2023年8月第3周大模型荟萃 2023.8.22版权声明:本文为博主chszs的原创文章,未经博主允许不得转载。 1、LLM-Adapters:可将多种适配器集成到大语言模型 来自新加坡科技设计大学和新加坡管理大学的研究人员发布了一篇题为《LLM-Adapters: An …...
win11 设置小任务栏
设置后效果 以下两种工具均可 1、StartAllBack 2、Start11...
在 React 中获取数据的6种方法
一、前言 数据获取是任何 react 应用程序的核心方面。对于 React 开发人员来说,了解不同的数据获取方法以及哪些用例最适合他们很重要。 但首先,让我们了解 JavaScript Promises。 简而言之,promise 是一个 JavaScript 对象,它将…...
Docker基础入门:常规软件安装与镜像加载原理
Docker基础入门:常规软件安装与镜像加载原理 一、Docker常规软件安装1.1、部署nginx1.2、部署tomcat1.3、部署elasticsearch1.4、如何部署kibana-->连接elasticsearch1.5、部署可视化工具 二、 镜像加载原理2.1、镜像是什么2.2、Docker镜像加速原理2.3、分层理解…...
redis初识
目录 前言: 核心全局命令 key过期实现方式 定时器实现方式 基于优先级队列/堆 redis特性 redis优点 redis单线程模型 redis单线程为什么效率这么高? 核心五种数据类型内部编码方式 前言: redis作为当前主流的内存数据库(…...
死锁的典型情况、产生的必要条件和解决方案
前言 死锁:多个线程同时被阻塞,他们中的一个或全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。 目录 前言 一、死锁的三种典型情况 (一)一个线程一把锁 (二)…...
日志搞不定?手把手教你如何使用Log4j2
系列文章目录 从零开始,手把手教你搭建Spring Boot后台工程并说明 Spring框架与SpringBoot的关联与区别 SpringBean生成流程详解 —— 由浅入深(附超精细流程图) Spring监听器用法与原理详解 Spring事务畅谈 —— 由浅入深彻底弄懂 Transactional注解 面试热点详解…...
基于Googlenet深度学习网络的交通工具种类识别matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ....................................................................................% 获…...
R语言04-R语言中的列表
概念 在R语言中,列表(List)是一种复杂的数据结构,用于存储不同类型的元素,包括向量、矩阵、数据框、函数等。列表是一种非常灵活的数据结构,可以将不同类型的数据组合在一起,类似于Python中的字…...
[Linux]进程概念
[Linux]进程概念 文章目录 [Linux]进程概念进程的定义进程和程序的关系Linux下查看进程Linux下通过系统调用获取进程标示符Linux下通过系统调用创建进程-fork函数使用 进程的定义 进程是程序的一个执行实例,是担当分配系统资源(CPU时间,内存…...
GEE/PIE遥感大数据处理与应用
随着航空、航天、近地空间等多个遥感平台的不断发展,近年来遥感技术突飞猛进。由此,遥感数据的空间、时间、光谱分辨率不断提高,数据量也大幅增长,使其越来越具有大数据特征。对于相关研究而言,遥感大数据的出现为其提…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
多元隐函数 偏导公式
我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式,给定一个隐函数关系: F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 🧠 目标: 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z、 …...
轻量级Docker管理工具Docker Switchboard
简介 什么是 Docker Switchboard ? Docker Switchboard 是一个轻量级的 Web 应用程序,用于管理 Docker 容器。它提供了一个干净、用户友好的界面来启动、停止和监控主机上运行的容器,使其成为本地开发、家庭实验室或小型服务器设置的理想选择…...
简单介绍C++中 string与wstring
在C中,string和wstring是两种用于处理不同字符编码的字符串类型,分别基于char和wchar_t字符类型。以下是它们的详细说明和对比: 1. 基础定义 string 类型:std::string 字符类型:char(通常为8位)…...
「Java基本语法」变量的使用
变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...
