基于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);
}

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

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

相关文章

在jupyter notebook中使用海龟绘图

首先&#xff0c;安装ipyturtle3 ref:ipyturtle3 PyPI pip install ipyturtle3然后&#xff0c;安装ipycanvas ipycanvas是一个需要安装在与JupyterLab实例相同环境的包。此外&#xff0c;您需要安装nodejs&#xff0c;并启用JupyterLab ipycanvas小部件。 所有这些都在ipy…

ARM--day7(cortex_M4核LED实验流程、异常源、异常处理模式、异常向量表、异常处理流程、软中断编程、cortex_A7核中断实验)

软中断代码&#xff1a;&#xff08;keil软件&#xff09; .text .global _start _start:1.构建异常向量表b resetb undef_interruptb software_interruptb prefetch_dataabortb data_abortb .b irqb fiq reset:2.系统一上电&#xff0c;程序运行在SVC模式1>>初始化SVC模…

Oracle 中 ROWNUM 使用问题记录

ROWNUM 使用问题记录(2023-08-17) Oracle 版本&#xff1a; 19.0.0.0.0 Enterprise现象&#xff1a;今天在项目遇到一个问题&#xff0c;测试人员反馈前一天能看到的数据今天看不到了 用表格举例&#xff0c;这是前一天看到的数据&#xff0c;有9、7、1 这几个数量信息 日期…

postgresql 的递归查询

postgresql 的递归查询功能很强大&#xff0c;可以实现传统 sql 无法实现的事情。那递归查询的执行逻辑是什么呢&#xff1f;在递归查询中&#xff0c;我们一般会用到 union 或者 union all&#xff0c;他们两者之间的区别是什么呢&#xff1f; 递归查询的执行逻辑 递归查询的…

NFTScan NFT API 在 DID Protocol 开发中的应用

自互联网发展以来&#xff0c;Web2.0 时代产生了网络社会&#xff0c;社会已经不再局限于地理边界&#xff0c;而 Web 3.0 引入了去中心化的理念&#xff0c;强调个体数据隐私和可信互操作性。在这个新的时代中&#xff0c;去中心化身份&#xff08;Decentralized Identifier 即…

linux中shell脚本——shell数组、正则表达式及文件三剑客之AWK

目录 一.shell数组 1.1.数组分类 1.2.定义数组方法 二.正则表达式 2.1.元字符 2.2.表示次数 2.3.位置锚定 2.4.分组 2.5.扩展正则表达式 三.文本三剑客之AWK 3.1.awk介绍及使用格式 3.2.处理动作 3.3.awk选项 3.4.awk处理模式 2.5.awk常见的内置变量 2.6.if条…

pytorch内存泄漏

问题描述&#xff1a; 内存泄漏积累过多最终会导致内存溢出&#xff0c;当内存占用过大&#xff0c;进程会被killed掉。 解决过程&#xff1a; 在代码的运行阶段输出内存占用量&#xff0c;观察在哪一块存在内存剧烈增加或者显存异常变化的情况。但是在这个过程中要分级确认…

uniapp快递信息

uni-app实现一个简易实用物流信息跟踪模板页面_后端物流跟踪模块_鱼翔涌底的博客-CSDN博客

Pytorch-day08-模型进阶训练技巧-checkpoint

PyTorch 模型进阶训练技巧 自定义损失函数动态调整学习率 典型案例&#xff1a;loss上下震荡 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BndMyRX0-1692613806232)(attachment:image-2.png)] 1、自定义损失函数 1、PyTorch已经提供了很多常用…

基于Jenkins构建生产CICD环境(上篇)

目录 环境概述 Jenkins简介 持续集成 持续集成的效益 持续集成的作用 持续集成的特点 持续交付 持续部署 Maven 介绍 安装配置Jenkins Jenkins配置 1、修改jenkins初始密码 2、安装 Jenkins 必要插件 环境概述 随着软件开发需求及复杂度的不断提高&#xff0c;团队…

conda使用教程

Conda介绍 conda可以理解为一个工具&#xff0c;也是一个可执行命令&#xff0c;其核心功能是包管理和环境管理。包管理与pip的使用方法类似似&#xff0c;环境管理则是允许用户方便滴安装不同版本的python环境并在不同环境之间快速地切换。 conda的设计理念 conda将几乎所有…

前端面试的计算机网络部分(3)每天10个小知识点

目录 系列文章目录前端面试的计算机网络部分&#xff08;1&#xff09;每天10个小知识点前端面试的计算机网络部分&#xff08;2&#xff09;每天10个小知识点 知识点21. 有哪些网络流量分析工具&#xff1f;如何利用它们来分析前端应用的网络请求&#xff1f;**22. 在进行前端…

怎样通过本地电脑搭建SFTP服务器,并实现公网访问?

本地电脑搭建SFTP服务器&#xff0c;并实现公网访问 文章目录 本地电脑搭建SFTP服务器&#xff0c;并实现公网访问1. 搭建SFTP服务器1.1 下载 freesshd 服务器软件1.3 启动SFTP服务1.4 添加用户1.5 保存所有配置 2. 安装SFTP客户端FileZilla测试2.1 配置一个本地SFTP站点2.2 内…

appium2 安装 和出现问题解决

1.安装环境 A macOS, Linux, or Windows operating systemNode.js version in the SemVer range ^14.17.0 || ^16.13.0 || >=18.0.0NPM version >= 8 (NPM is usually bundled with Node.js, but can be upgraded independently) 1.1只要安装nodejs最新版就好了 1.2安…

提升Python代理程序性能的终极解决方案:缓存、连接池和并发

在开发Python代理程序时&#xff0c;优化性能是至关重要的。本文将为你介绍一套终极解决方案&#xff0c;通过缓存、连接池和并发处理等技术&#xff0c;极大地提升Python代理程序的效率和稳定性。 游戏国内地更换虚拟含ip地址数据库地区 1.缓存技术 缓存是 .0-*-696ES2 0一…

el-table分页后序号连续的两种方法

实现效果&#xff1a; 第一页排序到10&#xff0c;第二页的排序应从11开始 实现方法一&#xff1a; 在el-table的序号列中使用template定义 <el-table><el-table-columnmin-width"10%"label"序号"><template slot-scope"scope"…

使用docker-compose.yml快速搭建开发、部署环境(nginx、tomcat、mysql、jar包、各种程序)以及多容器通信和统一配置

目录 docker-compose语法&#xff08;更多说明可查看下面代码&#xff09;imagehostnamecontainer_namevolumesnetworks yml文件的使用启动停止 开发环境&#xff08;这里以python为例&#xff09;部署环境nginxmysqltomcatjar包打包后的可执行程序 常见问题与解决方案多个容器…

网络协议的定义、组成和重要性?

什么是网络协议&#xff1f; 网络协议是在计算机网络中&#xff0c;用于规定通信实体之间进行数据传输和通信的规则集合。网络协议涵盖了各种通信细节&#xff0c;包括数据包格式、错误处理、数据传输速率等&#xff0c;是用于分组交换数据网络的一种协议&#xff0c;其任务仅…

HarmonyOS 设置全屏NoTitleBar

这篇很有用&#xff1a;玩转HarmonyOS 状态栏&标题栏&导航栏相关操作方法整理 配置页面全屏显示(在config.json中配置)&#xff1a; "metaData": {"customizeData": [{"name": "hwc-theme","value": "androi…

二、SQL,如何实现表的创建和查询

1、新建表格&#xff08;在当前数据库中新建一个表格&#xff09;&#xff1a; &#xff08;1&#xff09;基础语法&#xff1a; create table [表名]( [字段:列标签] [该列数据类型] comment [字段注释], [字段:列标签] [该列数据类型] comment [字段注释], ……&#xff0c…