基于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遥感大数据处理与应用
随着航空、航天、近地空间等多个遥感平台的不断发展,近年来遥感技术突飞猛进。由此,遥感数据的空间、时间、光谱分辨率不断提高,数据量也大幅增长,使其越来越具有大数据特征。对于相关研究而言,遥感大数据的出现为其提…...
今日算法(依旧二叉树)
class Solution { public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {//递归进行,加回溯过程if(rootq||rootp||rootNULL) return root;TreeNode*leftlowestCommonAncestor(root->left,p,q);TreeNode*rightlowestCommonAncestor…...
终极英雄联盟工具箱:如何用League Akari提升你的游戏效率与段位
终极英雄联盟工具箱:如何用League Akari提升你的游戏效率与段位 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League Akari是一款…...
终极Windows窗口管理指南:用AltSnap实现高效多任务处理
终极Windows窗口管理指南:用AltSnap实现高效多任务处理 【免费下载链接】AltSnap Maintained continuation of Stefan Sundins AltDrag 项目地址: https://gitcode.com/gh_mirrors/al/AltSnap 你是否厌倦了在Windows系统中精确点击窗口标题栏的繁琐操作&…...
避坑指南:STM32F407的ADC多通道采样,你的数据顺序真的对了吗?
STM32F407多通道ADC采样数据错位排查手册 在嵌入式开发中,ADC多通道采样是常见需求,但数据顺序错乱问题却让不少工程师深夜加班。上周有位同行发来求助:他的四通道温度监测系统运行两周后,突然出现通道数据交叉污染,导…...
第二章 小程序目录结构与核心文件详解
第二章 小程序目录结构与核心文件详解 📚 系列教程:微信小程序投票系统完整开发 🔗 上一章:第一章 - 微信小程序概述与开发准备 🔗 下一章:第三章 - WXML 所有表单组件与使用 2.1 完整目录结构 wx/page/ …...
免费APK安装器:Windows上安装Android应用的终极解决方案
免费APK安装器:Windows上安装Android应用的终极解决方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否曾想过在Windows电脑上直接运行Android应用&…...
基于开源LLM构建私有化智能体:从意图解析到安全执行的工程实践
1. 项目概述与核心价值最近在折腾一个挺有意思的开源项目,叫giocaizzi/ralph-copilot。乍一看这个名字,可能会让人联想到微软的 GitHub Copilot,但它的定位和实现方式其实非常不同。简单来说,这是一个基于开源大语言模型ÿ…...
TVA模型适配FPC材料疲劳差异
重磅预告:本专栏将独家连载系列丛书《智能体视觉技术与应用》部分精华内容,该书是世界首套系统阐述“因式智能体”视觉理论与实践的专著,特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan先生师从美国三院院士、“…...
从BERT到GPT-4:大语言模型的技术演进与应用实践
1. 从单向到双向:大语言模型如何重塑AI的认知边界如果你在2018年之前问我,一个AI模型能不能同时理解一句话里每个词的前后文关系,我会告诉你这很难。那时的主流模型,比如OpenAI的GPT初代,就像一个只能从左到右阅读的读…...
HOSFEM中矩阵向量乘法优化与几何因子重计算技术
1. 矩阵向量乘法在HOSFEM中的核心地位与挑战 高阶/谱有限元方法(HOSFEM)是求解偏微分方程(PDE)的重要工具,广泛应用于计算流体力学、结构力学和电磁学等领域。与传统低阶方法相比,HOSFEM能以更少的自由度达…...
