基于MongoDB的空间数据存储与查询

这篇具有很好参考价值的文章主要介绍了基于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: filedata
          authentication-database: admin
          #自动创建索引
          auto-index-creation: true
          connections-num-min-size: 5
          connections-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 {
 
    @Autowired
    private 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、增加圆形区域查询方法文章来源地址https://www.toymoban.com/news/detail-669322.html

/**
 * 圆形区域内查询
 * @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的空间数据存储与查询的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 分布式数据库NoSQL(四)——MongoDB 之聚合函数查询统计

    MongoDB 中聚合( aggregate )主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果,通常由聚合管道操作符和聚合表达式组合,完成数据处理。功能有点类似 Sql 语句中的 sum()、agv() 等。 目录 第1关:聚合管道操作符将文档定制格式输出(一) 常用聚合管道操作符

    2024年02月09日
    浏览(49)
  • Sql Server中查询数据库所有表及其数据总条数和占用空间

    1、查询某数据库中的所有数据表 SELECT name 数据表 FROM sysobjects WHERE xtype=\\\'u\\\' ORDER BY name 2、查询某数据库中的所有数据表及其数据总条数 SELECT a.name 数据表, b.rows 数据总条数 FROM sysobjects AS a INNER JOIN sysindexes AS b ON a.id = b.id WHERE ( a.type = \\\'u\\\' ) AND ( b.indid IN ( 0, 1 ) ) ORDER BY a.name,b.row

    2024年02月02日
    浏览(47)
  • 系列十三、查询数据库中某个库、表、索引等所占空间的大小

            information_schema数据库是MySQL出厂默认带的一个数据库,不管我们是在Linux中安装MySQL还是在Windows中安装MySQL,安装好后都会有一个数据库information_schema,这个库中存放了其他库的所有信息。 schemata表: 这个表里面主要是存储在mysql中的所有的数据库的信息。 tables表

    2024年02月01日
    浏览(44)
  • Python网络爬虫逆向分析爬取动态网页、使用Selenium库爬取动态网页、​编辑将数据存储入MongoDB数据库

    目录 逆向分析爬取动态网页 了解静态网页和动态网页区别 1.判断静态网页  2.判断动态网页  逆向分析爬取动态网页 使用Selenium库爬取动态网页 安装Selenium库以及下载浏览器补丁 页面等待  页面操作 1.填充表单 2.执行JavaScript 元素选取 Selenium库的find_element的语法使用格式如下

    2024年02月15日
    浏览(119)
  • 基于SqlSugar的开发框架循序渐进介绍(27)-- 基于MongoDB的数据库操作整合

    SqlSugar的开发框架本身主要是基于常规关系型数据库设计的框架,支持多种数据库类型的接入,如SqlServer、MySQL、Oracle、PostgreSQL、SQLite等数据库,非关系型数据库的MongoDB数据库也可以作为扩展整合到开发框架里面,通过基类的继承关系很好的封装了相关的基础操作功能,极大

    2023年04月13日
    浏览(47)
  • 【Mysql】X-DOC:Mysql数据库大量数据查询加速(定时JOB和存储过程应用案例)

    在某中台系统中,设计了大量的基础数据(维度数据、维度映射关系等)来支撑业务功能,业务表中存在大量的维度外键关联字段,其优点是可以实现前端的选择录入,数据校验,确保录入数据的准确性;缺点是在做业务报表时,需要做大量的维度关联(join)操作。 受限于

    2024年02月12日
    浏览(44)
  • (解析+源码)基于JAVA Swing+MySQL实现学生信息管理系统(增、删、改、查)数据库/文件存储

    本文适合 有一定JAVA编程基础(听过一点课的同学) 的同学“食用”,源代码都在文末 源代码(点击跳转) ,第四部分是各个模块的实现,新建一个工程把下面代码添加进去,然后在数据库里按id-username-password和id-name-sex-telephone-number-birthday-note创建两个表,在Connect.java里面将us

    2024年02月04日
    浏览(53)
  • mongodb 数据库管理(数据库、集合、文档)

    目录 一、数据库操作 1、创建数据库 2、删除数据库 二、集合操作 1、创建集合 2、删除集合 三、文档操作 1、创建文档 2、 插入文档 3、查看文档 4、更新文档 1)update() 方法 2)replace() 方法 创建数据库的语法格式如下: 如果数据库不存在,则创建数据库,否则切换到该数据

    2024年02月12日
    浏览(52)
  • [虚幻引擎 MongoDB Client 插件说明] DTMongoDB MongoDB数据库连接插件,UE蓝图可以操作MongoDB数据库增删改查。

    本插件可以在UE里面使用蓝图操作MongoDB数据库, 对数据库进行查询,删除,插入,替换,更新操作。 插件下载地址在文章最后。 Create MongoDB Client - 创建客户端对象 创建一个 MongoDB 客户端对象。 Connect By Url - 连接到数据库 Url :MongoDB的连接地址。 如 mongoDB://account:password@ip:

    2024年02月14日
    浏览(96)
  • MongoDB数据库从入门到精通系列文章之:MongoDB数据库百篇技术文章汇总

    MongoDB数据库系列文章持续更新中: 更多数据库内容请阅读博主数据库专栏,数据库专栏涵盖了Mysql、SQLServer、PostgreSQL、MongoDB、Oracle、Cassandra等数据库 数据库专栏 文章名称 文章链接 数据库安装部署系列之:部署Mongodb5.0.6高可用集群详细步骤 数据库安装部署系列之:部署M

    2024年02月11日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包