Encontre restaurantes com queries geoespaciais
Nesta página
Visão geral
A indexação geoespacial do MongoDB permite que você execute com eficiência queries espaciais em uma coleção que contém formas e pontos geoespaciais. Para mostrar os recursos geoespaciais e comparar diferentes abordagens, este tutorial guiará você pelo processo de escrever queries para um aplicativo geoespacial simples.
Este tutorial introduzirá brevemente os conceitos de índices geoespaciais, e então demonstrará seu uso com $geoWithin
, $geoIntersects
e $nearSphere
.
Suponha que você esteja projetando um aplicativo móvel para ajudar os usuários a encontrar restaurantes na cidade de Nova York. O aplicativo deve:
Determine a vizinhança atual do usuário usando
$geoIntersects
,Mostre o número de restaurantes nesse bairro usando
$geoWithin
eEncontre restaurantes dentro de uma distância especificada do usuário utilizando o
$nearSphere
.
Este tutorial utilizará um índice 2dsphere
para fazer query destes dados em geometria esférica.
Para mais informações sobre geometrias esféricas e planas, consulte Modelos Geoespaciais.
Distorção
A geometria esférica aparecerá distorcida quando visualizada em um mapa devido à natureza da projeção de uma esfera tridimensional, como a Terra, em uma superfície plana.
Por exemplo, pegue a especificação do quadrado esférico definido pelos pontos de latitude longitude (0,0)
, (80,0)
, (80,80)
e (0,80)
. A figura a seguir representa a área abrangida por esta região:
Procurando restaurantes
Pré-requisitos
Baixe os conjuntos de dados de exemplo de https://raw.githubusophyllument.com/mongodb/docs-assets/geospatial/neighborhoods.json e https://raw.githubusophyllument.com/mongodb/docs-assets/geospatial/restaurants.json. Eles contêm as coleções restaurants
e neighborhoods
respectivamente.
Após baixar os conjuntos de dados, importe-os para o banco de dados:
mongoimport <path to restaurants.json> -c=restaurants mongoimport <path to neighborhoods.json> -c=neighborhoods
Um índice geoespacial e quase sempre melhora o desempenho das consultas $geoWithin
e $geoIntersects
.
Como esses dados são geográficos, crie um índice 2dsphere
em cada coleção usando mongosh
:
db.restaurants.createIndex({ location: "2dsphere" }) db.neighborhoods.createIndex({ geometry: "2dsphere" })
Explorando os dados
Inspecione uma entrada na coleção recém-criada de restaurants
em mongosh
:
db.restaurants.findOne()
Esta query retorna um documento como o seguinte:
{ location: { type: "Point", coordinates: [-73.856077, 40.848447] }, name: "Morris Park Bake Shop" }
Este documento do restaurante corresponde ao local mostrado na seguinte figura:
Como o tutorial utiliza um índice do 2dsphere
, os dados de geometria no campo location
devem seguir o formato GeoJSON.
Agora inspecione uma entrada na coleção neighborhoods
:
db.neighborhoods.findOne()
Esta query retornará um documento como o seguinte:
{ geometry: { type: "Polygon", coordinates: [[ [ -73.99, 40.75 ], ... [ -73.98, 40.76 ], [ -73.99, 40.75 ] ]] }, name: "Hell's Kitchen" }
Essa geometria corresponde à região representada na figura a seguir:
Encontre o Bairro Atual
Supondo que o dispositivo móvel do usuário possa fornecer uma localização razoavelmente precisa para o usuário, é simples encontrar a vizinhança atual do usuário com $geoIntersects
.
Suponha que o usuário esteja localizado a -73.93414657 de longitude e 40.82302903 de latitude. Para localizar a vizinhança atual, você especificará um ponto usando o campo $geometry
especial no formato GeoJSON:
db.neighborhoods.findOne({ geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } })
Esta query retornará o seguinte resultado:
{ "_id" : ObjectId("55cb9c666c522cafdb053a68"), "geometry" : { "type" : "Polygon", "coordinates" : [ [ [ -73.93383000695911, 40.81949109558767 ], ... ] ] }, "name" : "Central Harlem North-Polo Grounds" }
Encontre todos os restaurantes no bairro
Você também pode fazer uma query para encontrar todos os restaurantes contidos em determinado bairro. Execute o seguinte em mongosh
para localizar o bairro que contém o usuário e, em seguida, conte os restaurantes dentro desse bairro:
var neighborhood = db.neighborhoods.findOne( { geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } } ) db.restaurants.find( { location: { $geoWithin: { $geometry: neighborhood.geometry } } } ).count()
Esta query dirá que há 127 restaurantes no bairro solicitado, visualizados na seguinte figura:
Encontre restaurantes a uma distância
Para encontrar restaurantes a uma distância específica de um ponto, você pode usar $geoWithin
com $centerSphere
para retornar resultados em ordem não classificada ou $nearSphere
com $maxDistance
se precisar de resultados classificados por distância.
Não classificado com $geoWithin
Para encontrar restaurantes dentro de uma região circular, utilize o $geoWithin
com $centerSphere
. $centerSphere
é uma sintaxe específica do MongoDB para denotar uma região circular especificando o centro e o raio em radianos.
$geoWithin
não retorna os documentos em nenhuma ordem específica, portanto, pode
mostrar ao usuário os documentos mais distantes primeiro.
A seguir, encontrará todos os restaurantes em um raio de cinco milhas do usuário:
db.restaurants.find({ location: { $geoWithin: { $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })
O segundo argumento do $centerSphere
aceita o raio em radianos, então você deve dividi-lo pelo raio da Terra em quilômetros. Consulte Calcular distância usando geometria esférica para obter mais informações sobre a conversão entre unidades de distância.
Classificado com $nearSphere
Você também pode usar $nearSphere
e especificar um termo $maxDistance
em metros. Isso retornará todos os restaurantes em um raio de oito quilômetros do usuário do mais próximo para o mais distante:
var METERS_PER_MILE = 1609.34 db.restaurants.find({ location: { $nearSphere: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] }, $maxDistance: 5 * METERS_PER_MILE } } })