Overview
En esta guía, aprenderá a consultar datos geoespaciales mediante el controlador de Scala. También podrá conocer los diferentes formatos de datos geoespaciales compatibles con MongoDB.
Los datos geoespaciales representan una ubicación geográfica en la superficie de la Tierra. Algunos ejemplos de datos geoespaciales son:
Ubicaciones de cines
Fronteras de los países
Rutas de paseos en bicicleta
Áreas para ejercitar perros en Nueva York
Datos de muestra
Los ejemplos de esta guía utilizan la colección theaters en la base de datos sample_mflix de los conjuntos de datos de muestra de Atlas. Para acceder a esta colección desde tu aplicación Scala, crea un MongoClient que se conecte a un clúster Atlas y asigna los siguientes valores a tus variables database y collection:
val database: MongoDatabase = mongoClient.getDatabase("sample_mflix") val collection: MongoCollection[Document] = database.getCollection("theaters")
Para aprender cómo crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de ejemplo, consulta la guía MongoDB Get Started.
Coordenadas en la Tierra
Para almacenar y realizar consultas sobre tus datos geoespaciales en MongoDB, utiliza GeoJSON. GeoJSON es un formato de datos creado por el Grupo de Trabajo de Ingeniería de Internet (IETF).
Esta es la ubicación de la sede de MongoDB en GeoJSON:
"location" : { "type": "Point", "coordinates": [-73.986805, 40.7620853] }
Para obtener información definitiva sobre GeoJSON, consulte la especificación oficial de IETF.
Posiciones GeoJSON
Una posición representa un único lugar en la Tierra y se define como un arreglo que contiene dos o tres valores numéricos:
Longitud en la primera posición (requerido)
Latitud en la segunda posición (obligatoria).
Elevación en la tercera posición (opcional)
Importante
Longitud y luego latitud
GeoJSON ordena las coordenadas como primero longitud y segundo latitud. Esto puede ser sorprendente, ya que las convenciones del sistema de coordenadas geográficas generalmente indican la latitud primero y la longitud después. Asegúrate de comprobar qué formato utilizan las demás herramientas con las que trabajas. Las herramientas populares, como OpenStreetMap y Google Maps, enumeran las coordenadas como latitud primero y longitud segundo.
Tipos GeoJSON
El tipo del objeto GeoJSON determina su forma geométrica. Las formas geométricas se componen de posiciones.
Aquí tienes algunos tipos comunes de GeoJSON y cómo puedes especificarlos con posiciones:
PointUna sola posición. Esto podría representar la ubicación de una escultura.LineString: arreglo de dos o más posiciones, formando así una serie de segmentos de línea. Esto podría representar la ruta de la Gran Muralla China.Polygon: Arreglo de posiciones en las que la primera y la última posición son iguales, encerrando algún espacio. Esto podría representar la tierra dentro de la Ciudad del Vaticano.
Para aprender más sobre las formas que puedes usar en MongoDB, consulta GeoJSON en el manual del Servidor.
Index
Para crear un índice 2dsphere, utiliza el asistente Indexes.geo2dsphere() para crear una especificación para el índice 2dsphere. Pase la especificación al método MongoCollection.createIndex() para crear el índice.
El siguiente ejemplo crea un índice 2dsphere en el campo "location.geo" en la colección theaters:
val indexObservable = collection.createIndex(Indexes.geo2dsphere("location.geo")) Await.result(indexObservable.toFuture(), Duration(10, TimeUnit.SECONDS))
Para obtener más información sobre los índices en el controlador de Scala, consulte la guía Optimizar consultas mediante el uso de índices.
Coordenadas en un plano 2D
Puedes almacenar datos geoespaciales usando x y coordenadas y en un plano euclidiano bidimensional. Las coordenadas en un plano bidimensional se denominan pares de coordenadas heredadas.
Los pares de coordenadas heredadas tienen la siguiente estructura:
{ "location" : [ x, y ] }
El valor del campo contiene un arreglo de dos valores en la que el primero representa el valor del eje x y el segundo representa el valor del eje y.
Index
Para consultar datos almacenados como pares de coordenadas heredados, debe agregar el campo que contiene dichos pares a un índice 2d. El siguiente fragmento crea un índice 2d en el campo coordinates utilizando el objeto Indexes:
val indexObservable = collection.createIndex(Indexes.geo2d("coordinates")) Await.result(indexObservable.toFuture(), Duration(10, TimeUnit.SECONDS))
Para obtener más información sobre los índices en el controlador de Scala, consulte la guía Optimizar consultas mediante el uso de índices.
Para obtener más información sobre legacy coordinate pairs, consulta la sección legacy coordinate pairs de la guía de Queries Geoespaciales en el manual del Server.
Tip
Operadores compatibles
Los índices esféricos (2dsphere) y planos (2d) admiten algunos, pero no todos, los mismos operadores del query. Para ver una lista completa de operadores y su compatibilidad con índices, consulta la sección de Operadores del query geoespaciales en la guía de Consultas geoespaciales del manual del servidor.
Query geoespacial
Las consultas geoespaciales consisten en un operador del query y formas GeoJSON como parámetros del query.
Operadores del query
Para query tus datos geoespaciales, utiliza uno de los siguientes operadores del query:
$near$geoWithin$nearSphere$geoIntersectsrequiere un índice 2dsphere
Puedes especificar estos operadores de consulta en el controlador Scala con los métodos near(), geoWithin(), nearSphere() y geoIntersects() del objeto Filters.
Para obtener más información sobre los operadores del query geoespacial, consulta la sección Operadores de Consulta Geoespacial de la guía Consultas Geoespaciales en el Manual del servidor.
Para ver una lista completa de los métodos asistentes de Filters, consulte la Filtros documentación de la API.
Parámetros de query
Para especificar una forma que se utilizará en una consulta geoespacial, utilice las clases Position, Point, LineString y Polygon del controlador de Scala.
Para obtener más información sobre las clases de formas de GeoJSON, consulte la paquete GeoJSON Documentación de la API.
Ejemplos de consultas geoespaciales
Los siguientes ejemplos utilizan la colección de MongoDB Atlas theaters en la sample_mflix base de datos de ejemplo. Puedes aprender a configurar tu propio clúster Atlas gratuito y a cargar el conjunto de datos de ejemplo en la guía «Primeros pasos con el controlador Scala».
Los ejemplos de esta sección requieren las siguientes importaciones:
import org.mongodb.scala.* import org.mongodb.scala.model.Indexes import org.mongodb.scala.model.Filters import org.mongodb.scala.model.Projections import com.mongodb.client.model.geojson.{Point, Polygon, Position} import java.util.Arrays import java.util.concurrent.TimeUnit import scala.concurrent.Await import scala.concurrent.duration.Duration
La colección theaters ya contiene un índice 2dsphere en el campo location.geo.
Query por Proximidad
Para buscar y devolver documentos desde el punto más cercano al más lejano, utilice el método near() del objeto Filters. El método near() construye una consulta con el operador de consulta $near.
El siguiente ejemplo devuelve documentos que se encuentran como máximo a 1000 metros de la instancia Point GeoJSON especificada, ordenados del más cercano al más lejano:
val refPoint = new Point(new Position(-73.986805, 40.7620853)) val findObservable = collection.find(Filters.near("location.geo", refPoint, Some(1000.0), Some(0.0))) val results = Await.result(findObservable.toFuture(), Duration(10, TimeUnit.SECONDS))
{"_id": {"$oid": "59a47287cfa9a3a73e51e8e2"}, "theaterId": 1908, "location": {"address": {"street1": "750 Seventh Ave", "city": "New York", "state": "NY", "zipcode": "10019"}, "geo": {"type": "Point", "coordinates": [-73.983487, 40.76078]}}} {"_id": {"$oid": "59a47286cfa9a3a73e51e838"}, "theaterId": 1448, "location": {"address": {"street1": "1880 Broadway", "city": "New York", "state": "NY", "zipcode": "10023"}, "geo": {"type": "Point", "coordinates": [-73.982094, 40.769882]}}}
Tip
MongoDB usa el mismo sistema de referencias que los satélites GPS para calcular geometrías sobre la Tierra.
Para aprender más sobre el operador $near, consulta la referencia $near en el manual del servidor.
Consulta dentro de un rango
Para buscar datos geoespaciales dentro de una forma específica, utilice el método geoWithin() del objeto Filters. El método geoWithin() construye una consulta con el operador de consulta $geoWithin.
El siguiente ejemplo busca cines en una sección de Long Island. El ejemplo aplica una proyección de modo que cada resultado incluya solo el campo location.address.city y excluya el campo _id:
val longIslandTriangle = new Polygon(Arrays.asList( new Position(-72.0, 40.0), new Position(-74.0, 41.0), new Position(-72.0, 39.0), new Position(-72.0, 40.0) )) val projection = Projections.fields( Projections.include("location.address.city"), Projections.excludeId() ) val geoWithinComparison = Filters.geoWithin("location.geo", longIslandTriangle) val findObservable = collection.find(geoWithinComparison).projection(projection) val results = Await.result(findObservable.toFuture(), Duration(10, TimeUnit.SECONDS)) results.foreach(doc => println(doc.toJson()))
{"location": {"address": {"city": "Baldwin"}}} {"location": {"address": {"city": "Levittown"}}} {"location": {"address": {"city": "Westbury"}}} {"location": {"address": {"city": "Mount Vernon"}}} {"location": {"address": {"city": "Massapequa"}}}
La siguiente figura muestra el polígono definido por la variable longIslandTriangle y los puntos que representan las ubicaciones de los cines que devuelve la consulta.

Para aprender más sobre el operador $geoWithin, consulta la referencia $geoWithin en el manual del Servidor.
Información Adicional
Para obtener más información sobre cómo realizar consultas geoespaciales, consulta Consultas geoespaciales en el manual del servidor.