赞
踩
MongoDB 中使用 GeoJSON对象 或 坐标对 描述空间地理数据。MongoDB使用 WGS84 参考系进行地理空间数据查询。
1、MongoDB支持空间数据的存储,数据类型需要限制为GeoJSON;
2、MongoDB可以为GeoJSON类型数据建立索引,提升空间查询的效率;
GeoJSON 对象格式
-
- <field>: { type: <GeoJSON type> , coordinates: <coordinates> }
GeoJSON 对象有两个filed,分别是 type 和 coordinates.其中,
type 指明是哪种空间地理数据类型
coordinates: 是描述 Geo对象的坐标数组,经度在前(经度取值范围 -180到 180),纬度在后(纬度取值范围是-90到90
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.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.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);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。