目录

地理空间查询运算符:

几何操作符说明:

查询操作符说明: 

地理空间聚集管道符:

准备工作:

1. mongodb中先插入几条数据:

2. 先给经纬度字段建立2dsphere索引。

地理位置查询案例:

给出一个经纬度,查询mongodb中与其他经纬度的距离

 mongodb的查询语句

Java代码实现:

给出经纬度和半径,从mongodb中查询该范围内的所有数

mongodb查询语句

Java代码实现

给出经纬度和半径构建圆形范围,从mongodb中查询是否与其他相交,重叠。

​mongodb实现

java代码实现

多个经纬度构建的几何范围查询

插入测试数据

判断几何图形面积是否相交

mongodb案例:

Java代码实现 


  • MongoDB地理空间查询可以解释平面或球体上的几何图形。
  • 2dsphere索引只支持球形查询(即在球形表面上解释几何图形的查询)。
  • 2d索引支持平面查询(即在平面上解释几何图形的查询)和一些球形查询。虽然2d索引支持一些球形查询,但是对这些球形查询使用2d索引可能会导致错误。如果可能,对球形查询使用2dsphere索引。

地理空间查询运算符:

几何操作符说明:

NameDescription
$box使用传统坐标对指定一个用于$geoWithin查询的矩形框 。2D索引支撑 $box
$center使用坐标(经纬度)和距离第一 一个圆进行范围查询。2D索引支撑$center
$centerSphere在使用球形几何图形时,使用传统坐标或GeoJSON格式指定一个圆来进行$geoWithin查询(在球面上定义一个园,进行范围查询)。2dsphere和 2D索引支持$centerSphere
$geometry地理空间几何查询符, 指定GeoJSON格式的类型后。可以配合用以下地理空间查询操作符 $geoWithin$geoIntersects$near, $nearSphere$geometry,进行地理查询.
$maxDistance指定最大距离以限制$near 和$nearSphere查询的结果。2dsphere2D索引支持 $maxDistance
$minDistance指定最小距离以限制$near 和$nearSphere查询的结果。2dsphere仅与索引一起使用。
$polygon指定要使用旧式坐标对进行 $geoWithin查询的面。2D索引支撑 $center
$uniqueDocs不推荐使用。修改$geoWithin$near查询以确保即使文档多次匹配查询,查询也会返回一次文档。

查询操作符说明: 

$geoIntersects查询与指定的GeoJSON几何形状相交的几何形状。2dsphere索引支持 $geoIntersects
$geoWithin查询与指定的GeoJSON几何重叠的几何。该2dsphere2D指标支持 $geoWithin
$near(平面上定圆形,查询该圆形内的数据)返回点附近的地理空间对象。需要地理空间索引。该2dsphere2D指标支持 $near
$nearSphere(球面上定圆形,查询该圆形内的数据)返回球体上某个点附近的地理空间对象。需要地理空间索引。该2dsphere2D指标支持 $nearSphere

地理空间聚集管道符:

StageStage
$geoNear根据与地理空间点的接近程度返回有序的文档流。为地理空间数据合并了$match、$sort和$limit功能。输出文档包含一个额外的距离字段,并且可以包含一个位置标识符字段。
$geoNear需要一个地理空间索引。

准备工作:

1. mongodb中先插入几条数据:

 db.ZHXCDIS.insert({
      "ZXDJDWD" : [  69.3,  89.2 ],    //经纬度
      "BJ" : 10.0,      //半径
      "name": "面馆1"
     })
db.ZHXCDIS.insert({
      "ZXDJDWD" : [  69.4,  89.3 ],   //经纬度
      "BJ" : 20.0,   //半径
      "name": "面馆2"
     })
db.ZHXCDIS.insert({
      "ZXDJDWD" : [  69.5,  89.4 ],    //经纬度
      "BJ" : 30.0,   //半径
      "name": "面馆3"
     }) 

2. 先给经纬度字段建立2dsphere索引。

▼ 建立索引的字段一定要是数组或者对象,不然创建不了 # 2d不能写成2D

  • 2d索引,用于存储和查找平面上的点。(二维平面)
  • 2dsphere索引,用于存储和查找球面上的点,同时它支持数据存储为GeoJSON 和传统坐标。(查询地球上真实的距离用该索引)

创建索引的例子

  • db.你的Collection名字.createIndex({ 改成你要建立索引的字段名字 : "索引名字" })
  • db.ZHXCDIS.createIndex({ZXDJDWD : "2dsphere"})

地理位置查询案例:

  • 给出一个经纬度,查询mongodb中与其他经纬度的距离

3种距离单位

  • 米(meters)
  • 平面单位(flat units,可以理解为经纬度的“一度” )
  • 弧度(radians) :地球表面1弧度距离约为6378137米, 0.001弧度距离为6378米

 mongodb的查询语句

  • ZHXCDIS是Collection的名字,其他都是固定写法 
  • 若需要距离单位为米 则指定 distanceMultiplier: 6378137,
  • 千米 distanceMultiplier: 6378 (不指定该属性,则返回两点相差的弧度)

db.ZHXCDIS.aggregate({
    $geoNear:{
        near:[0,0],         //中括号中写经度纬度
        spherical:true,        //表示使用是否采用球面几何计算 (false则返回平面单位
        distanceMultiplier: 6378137,  //要和spherical:true同时使用,
        distanceField:"distance"    //给返回结果起一个叫distance的别名
        }})

/**
  查询的结果,会根据距离大小自动排序


    "_id" : ObjectId("6204c76ef73f965f1d3e5542"), 
    "ZXDJDWD" : [
        69.3, 
        89.2
    ], 
    "BJ" : 10.0, 
    "name" : "面馆1", 
    "distance" : 5617637.110091394   //相差的距离
}

    "_id" : ObjectId("6204c76ef73f965f1d3e5543"), 
    "ZXDJDWD" : [
        69.4, 
        89.3
    ], 
    "BJ" : 20.0, 
    "name" : "面馆2", 
    "distance" : 5624962.261152434   //相差的距离
}

    "_id" : ObjectId("6204c76ef73f965f1d3e5544"), 
    "ZXDJDWD" : [
        69.5, 
        89.4
    ], 
    "BJ" : 30.0, 
    "name" : "面馆3", 
    "distance" : 5632325.494106238   //相差的距离
}
**/

Java代码实现:

Aggregation aggregation = Aggregation.newAggregation(Aggregation.geoNear(
                    NearQuery.near(ZXDJD, ZXDWD) //经纬度
                            .spherical(true)    //是否采用球面几何计算
                            .distanceMultiplier(6378137D), "distance")); //是别名distance
/*参数一:构造的条件;参数二:表示你要查询mongodb的哪个Collection;参数三:查询的结果封装到实体类*/
List<DisasterOtherDTO> DisasterOtherDTOs = mongoTemplate.aggregate(aggregation, "ZHXCDIS",DisasterOtherDTO.class ).getMappedResults();
          

点面关系 

  • 给出经纬度和半径,从mongodb中查询该范围内的所有数

mongodb查询语句

//ZHXCDIS是collection的名字,ZXDJDWD是添加了2dsphere的字段,其他固定写法

//查询最远12500米半径,最近200米半径圆形范围内的所有数据

db.ZHXCDIS.find({
     ZXDJDWD:{
     $nearSphere:{
          type: "point",      //指定GeoJson类型为一个点, 
          coordinates: [117.0,39.0]   //经纬度(坐标)
     },
     $maxDistance: 12500,    //最远距离 ,查询坐标12500米内(单位:米)
     $minDistance:200        //最近距离,查询坐标200米外的数据(单位:米)
    }
})

Java代码实现

Point point = new Point(117.0, 39.0);
Query query = new Query(Criteria.where("ZXDJDWD") //经纬度字段
        .nearSphere(point)    //经纬度
        .maxDistance(12500d / 6378137d)    //最大距离 (这里一定要除以地球的半径(6378137),得出地弧度)
        .minDistance(200d / 6378137d));    //最近距离 (这里一定要除以地球的半径(6378137))

List<DisasterEntity> disasterEntities = mongoTemplate.find(query, DisasterEntity.class);
  • 给出经纬度和半径构建圆形范围,从mongodb中查询是否与其他相交,重叠。

ps:Mongodb中的点面关系,没有直接判断是否相交的功能,只能曲线救国。拿两个圆形范围的半径和,在得到两个圆心的距离,相比即可得出是否相交

逻辑:

  • 计算出经纬度和其他经纬度距离
  • 计算出半径和
  • 筛选出半径和比距离大的数据

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LuK5aSp5bCx5Yqq5Yqb,size_20,color_FFFFFF,t_70,g_se,x_16mongodb实现

 db.getCollection("ZHXCDIS").aggregate([
     {$geoNear:{                  //第一段聚合,先查询出距离,赋值给distance
          near:[69.3,89.2],
          spherical:true,        
          distanceMultiplier: 6378137,  
          distanceField:"distance",
          }},
     {"$addFields":{           //第二段聚合,计算出半径和赋值给num
          "num": {$add:["$BJ",20]}, //这个相当于我们给半径加20,然后将结果赋值给num
     }},
     {                                 
        "$redact": {                //第三阶段,筛选出半径和大于等于距离的数据,证明有相交
            "$cond": [
                { "$gte": [ "$num","$distance"] },    //$num和$distance等同于上面的
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

//发布博客后格式乱了,看这里

$redact:
  根据字段所处的document结构的级别,对文档进行“修剪”,它通常和“判断语句if-else”结合使用即$cond。 
  $redact可选值有3个: 
   1)$$DESCEND:包含当前document级别的所有fields。当前级别字段的内嵌文档将会被继续检测。 
   2)$$PRUNE:不包含当前文档或者内嵌文档级别的所有字段,不会继续检测此级别的其他字段,即使这些字段的内嵌文档持有相同的访问级别。 
   3)$$KEEP:包含当前文档或内嵌文档级别的所有字段,不再继续检测此级别的其他字段,即使这些字段的内嵌文档中持有不同的访问级别。 

java代码实现

 /**
     * 判断新建灾害现场和未结束的是否相交
     * @param ZXDJD 经度
     * @param ZXDWD 维度
     * @param BJ 半径
     * @return 返回相交距离最近的数据
     */
    private DisasterOtherDTO crossDisasterRange(Double ZXDJD, Double ZXDWD, Double BJ){
       
        //计算出半径和,赋值给num属性
        ArithmeticOperators.Add add = ArithmeticOperators.Add.valueOf("$BJ").add(BJ);
        AddFieldsOperation build =
                Aggregation.addFields().addFieldWithValue("num",add).build();
        //先查询出距离,赋值给distance
        GeoNearOperation distance1 = Aggregation.geoNear(
                NearQuery.near(ZXDJD,ZXDWD)
                        .spherical(true)
                        .distanceMultiplier(6378137d)), "distance");

        //筛选出半径和比距离大的数据,证明有相交
        Criteria condition = Criteria.where("num").gte("$distance");
        AggregationExpression conditionExpression = ConditionalOperators.Cond.when(condition).thenValueOf("$$KEEP")
                .otherwise("$$PRUNE");
        RedactOperation redact = Aggregation.redact(conditionExpression);

        //管道聚合查询,返回有相交的数据
        Aggregation aggregation = Aggregation.newAggregation(distance1,build,redact);
        List<DisasterOtherDTO> results = mongoTemplate.aggregate(aggregation, "ZHXCDIS", DisasterOtherDTO.class).getMappedResults();
        return results;
    }

多个经纬度构建的几何范围查询

插入测试数据

ps: 最后的一个经纬度一定要和第一个相同,这样才能闭合

db.demo.insertMany([{
     "name":"测试地点1",
     jw:{       //这是一个geoJson对象
          "type":"Polygon",   // 表示多边形几何
          "coordinates":[[          //结构必须是 [[[经度,维度],[经度,维度]]],三个中括号不可变
            [112.67097473144531,33.338559712732525], //首位必须一样才能闭合
            [112.78495788574217,33.338559712732525],
            [112.78495788574217,33.40679724595547],
            [112.67097473144531,33.40679724595547],
            [112.67097473144531,33.338559712732525]  //首位必须一样才能闭合
          ]]
     }
},{
     "name":"测试地点2",
     jw:{
          "type":"Polygon",
          "coordinates":[[
            [112.79869079589844,33.25476662931654],
            [112.92915344238281,33.25476662931654],
            [112.92915344238281,33.4039312002347],
            [112.79869079589844,33.4039312002347],
            [112.79869079589844,33.25476662931654]
          ]]
     }
},
{
     "name":"测试地点3",
     jw:{
          "type":"Polygon",
          "coordinates":[[
            [112.66273498535156,33.246153192679756],
            [112.7911376953125,33.246153192679756],
            [112.7911376953125,33.31388929028309],
            [112.66273498535156,33.31388929028309],
            [112.66273498535156,33.246153192679756]
          ]]
     }
},
{
     "name":"测试地点4",
     jw:{
          "type":"Polygon",
          "coordinates":[[
            [112.59613037109375,33.34085428063472],
            [112.65380859375,33.34085428063472],
            [112.65380859375,33.40622404437544],
            [112.59613037109375,33.40622404437544],
            [112.59613037109375,33.34085428063472]
          ]]
     }
}
])

db.demo.renameCollection('coordinates')

建索引

db.demo.createIndex(jw.coordinates,"2dsphere")   

判断几何图形面积是否相交

mongodb案例:

db.demo.find({
     jw: {   // coordinates是保存经纬度的字段
       $geoIntersects: {   //$geoIntersects: 查询相交的几何形状,$geoWithin:查询重叠
          $geometry: {          // 为地理空间查询运算符指定GeoJSON格式的几何
             type: "Polygon" ,  // 指定GeoJSON格式的几何类型为:Polygon,表示查询多边形
             coordinates: [[     //经纬度构建的多半形,
           [112.76195526123045,33.23064686752627],
           [112.91267395019531,33.23064686752627],
           [112.91267395019531,33.37411872061922],
           [112.76195526123045, 33.37411872061922],
           [112.76195526123045,33.23064686752627]
             ]]
          }
       }
     }
   }
)

注意:

  • 在插入数据的时候coordinates(经纬度)的结构必须是 [[[经度,维度],[经度,维度]]],假如说结构写成[[经度,维度],[经度,维度]],会出现以下的问题。
  • 当你给出经纬度构建一个几何图形,查询相交的时候,必须像图里红色四边形一样,与图中黑色四边形的角(经纬度点)相交才能查询出相交的数据。
  • 如果只是像蓝色四边形一样,与黑色多边形的边相交,mongodb查询不到相交的数据。
  • watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LuK5aSp5bCx5Yqq5Yqb,size_20,color_FFFFFF,t_70,g_se,x_16      

Java代码实现 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LuK5aSp5bCx5Yqq5Yqb,size_20,color_FFFFFF,t_70,g_se,x_16

如有问题还请大佬们多多指正

参考:$盒_MonogDB 中文网 (mongodb.net.cn)

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐