当前位置: 首页 > news >正文

基于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支持空间数据的存储&#xff0c;数据类型需要限制为GeoJSON; 2、MongoDB可以为GeoJSON类型数据建立索引&#xff0c;提升空…...

jquery中pdf的上传、下载及excel导出

jquery中pdf的上传、下载及excel导出 1.PDF上传 pdfUpload2. pdf下载和excel导出用的一种方法&#xff0c;并且需要引入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 的一个插件&#xff0c;这里就不扯了&a…...

C语言练习1(巩固提升)

C语言练习1 选择题 前言 “人生在勤&#xff0c;勤则不匮。”幸福不会从天降&#xff0c;美好生活靠劳动创造。全面建成小康社会的奋斗目标&#xff0c;为广大劳动群众指明了光明的未来&#xff1b;全面建成小康社会的历史任务&#xff0c;为广大劳动群众赋予了光荣的使命&…...

eCharts热力图Y轴左上角少一块

问题&#xff1a; 如图 在图例的左上角 Y轴会少一块 官方demo https://echarts.apache.org/examples/zh/editor.html?cheatmap-cartesian 事实上 把官方demo的左上角坐标 [ 6, 0, 1 ] 修改为 [ 6, 0, 0 ] 后 依旧会出现该问题 查遍文档 并无解释 也没有任何配置项可解决…...

RabbitMQ介绍

RabbitMQ的概念 RabbitMQ 是一个消息中间件&#xff1a;它接受并转发消息。你可以把它当做一个快递站点&#xff0c;当你要发送一个包裹时&#xff0c;你把你的包裹放到快递站&#xff0c;快递员最终会把你的快递送到收件人那里&#xff0c;按照这种逻辑 RabbitMQ 是 一个快递…...

玩转软件|钉钉个人版内测启动:AI探索未来的工作方式

目录 前言 正文 AI为核心&#xff0c;个人效率为王&#xff01; 指令中心&#xff0c;解锁AI技巧&#xff01; 灵感Store&#xff0c;探索更多可能&#xff01; 未来的AI&#xff0c;即将问世&#xff01; 个人内测体验 前言 重磅消息&#xff1a;钉钉个人版在8月16日正…...

【Linux】一张图了解系统文件

首先先认识磁盘结构 系统文件分布图 文件查找 文件删除 文件的增删改查都是围绕inode来完成的&#xff0c;所以当我们要进行文件删除的时候&#xff0c;只需要通过inode来获取到它对应的block bitmap和inode bitmap数据块容器和保存文件属性的位置置为 0即可 &#xff0c;如果想…...

自动化测试平台seldom-platform部署及使用

介绍 seldom-platform是一个基于seldom测试框架的测试平台 项目地址&#xff1a;https://github.com/SeldomQA 文档&#xff1a;seldom 语雀 首先&#xff0c;专门为seldom测试框架提供平台化支持。其次&#xff0c;只负责自动化测试项目的解析、执行用例&#xff0c;当然…...

2023年8月第3周大模型荟萃

2023年8月第3周大模型荟萃 2023.8.22版权声明&#xff1a;本文为博主chszs的原创文章&#xff0c;未经博主允许不得转载。 1、LLM-Adapters&#xff1a;可将多种适配器集成到大语言模型 来自新加坡科技设计大学和新加坡管理大学的研究人员发布了一篇题为《LLM-Adapters: An …...

win11 设置小任务栏

设置后效果 以下两种工具均可 1、StartAllBack 2、Start11...

在 React 中获取数据的6种方法

一、前言 数据获取是任何 react 应用程序的核心方面。对于 React 开发人员来说&#xff0c;了解不同的数据获取方法以及哪些用例最适合他们很重要。 但首先&#xff0c;让我们了解 JavaScript Promises。 简而言之&#xff0c;promise 是一个 JavaScript 对象&#xff0c;它将…...

Docker基础入门:常规软件安装与镜像加载原理

Docker基础入门&#xff1a;常规软件安装与镜像加载原理 一、Docker常规软件安装1.1、部署nginx1.2、部署tomcat1.3、部署elasticsearch1.4、如何部署kibana-->连接elasticsearch1.5、部署可视化工具 二、 镜像加载原理2.1、镜像是什么2.2、Docker镜像加速原理2.3、分层理解…...

redis初识

目录 前言&#xff1a; 核心全局命令 key过期实现方式 定时器实现方式 基于优先级队列/堆 redis特性 redis优点 redis单线程模型 redis单线程为什么效率这么高&#xff1f; 核心五种数据类型内部编码方式 前言&#xff1a; redis作为当前主流的内存数据库&#xff08…...

死锁的典型情况、产生的必要条件和解决方案

前言 死锁&#xff1a;多个线程同时被阻塞&#xff0c;他们中的一个或全部都在等待某个资源被释放。由于线程被无限期地阻塞&#xff0c;因此程序不可能正常终止。 目录 前言 一、死锁的三种典型情况 &#xff08;一&#xff09;一个线程一把锁 &#xff08;二&#xff09;…...

日志搞不定?手把手教你如何使用Log4j2

系列文章目录 从零开始&#xff0c;手把手教你搭建Spring Boot后台工程并说明 Spring框架与SpringBoot的关联与区别 SpringBean生成流程详解 —— 由浅入深(附超精细流程图) Spring监听器用法与原理详解 Spring事务畅谈 —— 由浅入深彻底弄懂 Transactional注解 面试热点详解…...

基于Googlenet深度学习网络的交通工具种类识别matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ....................................................................................% 获…...

R语言04-R语言中的列表

概念 在R语言中&#xff0c;列表&#xff08;List&#xff09;是一种复杂的数据结构&#xff0c;用于存储不同类型的元素&#xff0c;包括向量、矩阵、数据框、函数等。列表是一种非常灵活的数据结构&#xff0c;可以将不同类型的数据组合在一起&#xff0c;类似于Python中的字…...

[Linux]进程概念

[Linux]进程概念 文章目录 [Linux]进程概念进程的定义进程和程序的关系Linux下查看进程Linux下通过系统调用获取进程标示符Linux下通过系统调用创建进程-fork函数使用 进程的定义 进程是程序的一个执行实例&#xff0c;是担当分配系统资源&#xff08;CPU时间&#xff0c;内存…...

GEE/PIE遥感大数据处理与应用

随着航空、航天、近地空间等多个遥感平台的不断发展&#xff0c;近年来遥感技术突飞猛进。由此&#xff0c;遥感数据的空间、时间、光谱分辨率不断提高&#xff0c;数据量也大幅增长&#xff0c;使其越来越具有大数据特征。对于相关研究而言&#xff0c;遥感大数据的出现为其提…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...