一个Mongodb案例-使用地理信息查询酒店

学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第79篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关注威赞。谢谢。

Mongodb提供了方便的地理位置信息存储和查询方法。并提供了二维平面索引和二维空间索引,来提高查询效率。说到这里,躁动不安想要改变世界的程序员是否就有一些想法了呢?动起我们改变世界的手,创造出来一个又一个基于地图的程序来改变人们的生活。好了,Mongodb的官方人员也有同样的想法,所以直接在官方文档上给出来一个基于地图的使用示例。本文就为你整理介绍官方文档中给出的这个精彩的案例。

概述

mongodb的地理信息索引能够方便快速的让用户查询包含地理信息的集合。包括查询地理信息位置,地理信息覆盖范围查询和计算等。为了展现mongodb在地理信息处理的能力和地理信息不同的处理方法,本文向你介绍了一个编写简单地图应用查询的过程。

本文简单介绍了地理信息索引的概念,然后演示了使用方法$geoWithin, $geoIntersects和$nearSphere查询地理信息。

假设你现在正在研发一个小的地图应用,来帮助客户查找纽约的酒店。这个应用需要具备下面的功能:

  • 使用$geoIntersects确认用户当前街区的地理位置信息。
  • 使用$geoWithin展示该街区的酒店数量
  • 使用$nearSphere查找用户附近几公里内的酒店。

本文使用二维空间索引来查询这些空间信息。

投影畸变

将三维空间投射到平面时,地理信息展现会出现畸变。如将地球投射到平面地图时,就会产生这种畸变。例如,将经纬度范围在四个点(0,0),(80,0),(80,80),(0,80)投射到平面地图时,会出现下图所示的畸变。

地球是个三维球形,从赤道到北极组建变小。所以地球上这四个点围城的区域,投射到平面时,靠近极点的位置,会成为弧形。

酒店查询

数据准备

官网给出两个地址下载两份测试数据集

  • neighborhoods.json

https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.json

  • restaurants.json

https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json

这两份数据集记录了酒店的位置信息和城市的地理信息。如果下载有困难,用户可以到威赞上传的资源当中去查找。

下载完成这两份数据集后,将这两份数据导入数据库。

mongoimport <path to restaurants.json> -c=restaurants
mongoimport <path to neighborhoods.json> -c=neighborhoods

如果使用命令有困难,也可以使用mongodb compass来import数据。

导入完成后,构建二维空间索引

db.restaurants.createIndex({ location: "2dsphere" })
db.neighborhoods.createIndex({ geometry: "2dsphere" })

浏览数据

查看一条酒店的信息

db.restaurants.findOne()

返回结果

{
    "_id": {
      "$oid": "55cba2476c522cafdb053add"
    },
    "location": {
      "coordinates": [
        -73.856077,
        40.848447
      ],
      "type": "Point"
    },
    "name": "Morris Park Bake Shop"
  }

地图上显示酒店信息如下

查询一个街区的数据

db.neighborhoods.findOne()

返回结果

{
   geometry: {
      type: "Polygon",
      coordinates: [[
         [ -73.99, 40.75 ],
         ...
         [ -73.98, 40.76 ],
         [ -73.99, 40.75 ]
      ]]
    },
    name: "Hell's Kitchen"
}

地图上展示这个街区的样子

查找当前所在街区

假设用户的移动设备可以获得相对准确的位置信息。那么,使用$geoIntersects就可以很容易的获得用户的街区信息。文档中假设用户的经纬度坐标是(-73.93414657,40.82302903)。使用该坐标获取街区信息。

db.neighborhoods.find({geometry: {$geoIntersects: {$geometry: {type: "Point", coordinates: [-73.93414657, 40.82302903]}}}})

返回结果

{
    "_id" : ObjectId("55cb9c666c522cafdb053a68"),
    "geometry" : {
        "type" : "Polygon",
        "coordinates" : [
            [
                [
                    -73.93383000695911,
                    40.81949109558767
                ],
                ...
            ]
        ]
    },
    "name" : "Central Harlem North-Polo Grounds"
}

查找当前街区的所有酒店

前面依据用户的手机获取到了定位信息,查到了用户所在的街区。现在依据用户的所在的街区,查询出该街区所有酒店信息。

var neighborhood = db.neighborhoods.findOne( { geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } } )
db.restaurants.find( { location: { $geoWithin: { $geometry: neighborhood.geometry } } } ).count()

该查询发返回127个酒店数据,放到地图上展示如下。

查询指定距离内的酒店信息

用户可以使用$geoWithin方法和$centerSphere方法,查询出在指定范围内的酒店信息。该方法返回的数据是没有进行排序的。或者使用$nearSphere和$maxDistance方法,返回按照距离排序的信息。

使用$geoWithin查询

查找在指定半径范围内的酒店,使用方法$geoWithin, $centerShpere. 其中$centerSphere方法,是mongodb通过指定点和半径在地理空间内确定圆形的方法。

$geoWithin返回数据并没有排序,因此有可能会将最远的数据放在最前面。

查询附近5营利范围内的酒店

db.restaurants.find({ location:
   { $geoWithin:
      { $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })

其中$centerSphere的第二个参数,接收的是弧度信息。所以要除以地球的半径。

使用$nearSphere查询

用户可以使用$nearSphere和方法$maxDistance组合查询,返回结果按照距离由近到远进行排序。

var METERS_PER_MILE = 1609.34
db.restaurants.find({ location: { $nearSphere: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] }, $maxDistance: 5 * METERS_PER_MILE } } })

  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

威赞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值