Overview
MongoDB's El indexación geoespacial permite ejecutar queries espaciales de manera eficiente en una colección que contiene formas y puntos geoespaciales. Para mostrar las capacidades de las funcionalidades geoespaciales y comparar diferentes enfoques, este tutorial te guiará a través del proceso de escribir queries para una aplicación geoespacial sencilla.
Este tutorial presentará brevemente los conceptos de los índices geoespaciales y, a continuación, demostrará su uso con $geoWithin, $geoIntersects y $nearSphere.
Supón que estás diseñando una aplicación móvil para ayudar a los usuarios a encontrar restaurantes en la ciudad de Nueva York. La aplicación debe:
Determina el vecindario actual del usuario usando
$geoIntersects,Muestra el número de restaurantes en ese barrio utilizando
$geoWithin, yEncuentra restaurantes dentro de una distancia especificada del usuario utilizando
$nearSphere.
Este tutorial utilizará un índice 2dsphere para query estos datos sobre geometría esférica.
Para obtener más información sobre geometrías esféricas y planas, consulte Modelos geoespaciales.
Distorsión
La geometría esférica parecerá distorsionada cuando se visualiza en un mapa debido a la naturaleza de proyectar una esfera tridimensional, como la tierra, sobre un plano plano.
Por ejemplo, toma la especificación del cuadrado esférico definido por los puntos de longitud y latitud (0,0), (80,0), (80,80) y (0,80). La siguiente figura muestra el área cubierta por esta región:

Buscando restaurantes
Requisitos previos
Descargue los conjuntos de datos de ejemplo desde
https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.json y https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json. Estos contienen las colecciones restaurants y neighborhoods respectivamente.
Después de descargar los conjuntos de datos, impórtalos en la base de datos:
mongoimport <path to restaurants.json> -c=restaurants mongoimport <path to neighborhoods.json> -c=neighborhoods
Un índice geoespacial, y casi siempre mejora el rendimiento de $geoWithin y $geoIntersects consultas.
Como estos datos son geográficos, crea un índice 2dsphere en cada colección utilizando mongosh:
db.restaurants.createIndex({ location: "2dsphere" }) db.neighborhoods.createIndex({ geometry: "2dsphere" })
Exploración de los datos
Inspecciona una entrada en la nueva colección restaurants en mongosh:
db.restaurants.findOne()
Esta query devuelve un documento como el siguiente:
{ location: { type: "Point", coordinates: [-73.856077, 40.848447] }, name: "Morris Park Bake Shop" }
Este documento de restaurante corresponde a la ubicación que se muestra en la siguiente figura:

Debido a que el tutorial utiliza un índice 2dsphere, los datos de geometría en el campo location deben cumplir con el formato GeoJSON.
Ahora inspeccione una entrada en la colección neighborhoods:
db.neighborhoods.findOne()
Esta query devolverá un documento similar al siguiente:
{ geometry: { type: "Polygon", coordinates: [[ [ -73.99, 40.75 ], ... [ -73.98, 40.76 ], [ -73.99, 40.75 ] ]] }, name: "Hell's Kitchen" }
Esta geometría corresponde a la región representada en la siguiente figura:

Encuentra el vecindario actual
Suponiendo que el dispositivo móvil del usuario pueda proporcionar una ubicación razonablemente precisa para el usuario, es sencillo encontrar el vecindario actual del usuario con $geoIntersects.
Supón que el usuario se encuentra en la longitud -73.93414657 y latitud 40.82302903. Para encontrar el vecindario actual, deberás especificar un punto utilizando el campo especial $geometry en formato GeoJSON:
db.neighborhoods.findOne({ geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } })
Esta consulta devolverá el siguiente resultado:
{ "_id" : ObjectId("55cb9c666c522cafdb053a68"), "geometry" : { "type" : "Polygon", "coordinates" : [ [ [ -73.93383000695911, 40.81949109558767 ], ... ] ] }, "name" : "Central Harlem North-Polo Grounds" }
Buscar todos los restaurantes del barrio
También puedes hacer una query para encontrar todos los restaurantes en un barrio determinado. Ejecute lo siguiente en mongosh para encontrar el vecindario que contenga al usuario y luego cuente los restaurantes dentro de ese vecindario:
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 te indicará que hay 127 restaurantes en el vecindario solicitado, visualizados en la siguiente figura:

Encontrar restaurantes dentro de una distancia
Para encontrar restaurantes dentro de una distancia específica de un punto, puedes usar $geoWithin con $centerSphere para devolver resultados en un orden no ordenado, o $nearSphere con $maxDistance si necesitas resultados ordenados por distancia.
Sin ordenar con $geoWithin
Para encontrar restaurantes dentro de una región circular, utiliza $geoWithin con $centerSphere. $centerSphere es una sintaxis específica de MongoDB para denotar una región circular especificando el centro y el radio en radianes.
$geoWithin no devuelve los documentos en un orden específico, por lo que puede mostrarle al usuario primero los documentos más lejanos.
Lo siguiente encontrará todos los restaurantes dentro de cinco millas del usuario:
db.restaurants.find({ location: { $geoWithin: { $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })
$centerSphere El segundo argumento acepta el radio en radianes, por lo que debes dividirlo por el radio de la tierra en millas. Consulta Convertir distancia a radianes con operadores esféricos para obtener más información sobre la conversión entre unidades de distancia.
Ordenado con $nearSphere
También puede usar $nearSphere y especificar un término de $maxDistance en metros. Esto devolverá todos los restaurantes dentro de cinco millas del usuario en orden ordenado desde el más cercano al más lejano:
var METERS_PER_MILE = 1609.34 db.restaurants.find({ location: { $nearSphere: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] }, $maxDistance: 5 * METERS_PER_MILE } } })