Docs Menu
Docs Home
/ / /
Kotlin Coroutine
/ / /

Search Geospatially

On this page

  • Overview
  • Coordinates on Earth
  • GeoJSON Positions
  • GeoJSON Types
  • Index
  • Coordinates on a 2D Plane
  • Index
  • Geospatial Queries
  • Query Operators
  • Query Parameters
  • Examples
  • Query by Proximity
  • Query Within a Range

In this guide, you can learn how to search geospatial data with the MongoDB Kotlin Driver, and the different geospatial data formats supported by MongoDB.

Geospatial data is data that represents a geographical location on the surface of the Earth. Examples of geospatial data include:

  • Locations of movie theaters

  • Borders of countries

  • Routes of bicycle rides

  • Dog exercise areas in New York City

To store and query your geospatial data in MongoDB, use GeoJSON. GeoJSON is a data format created by the Internet Engineering Task Force (IETF).

Here is the location of MongoDB headquarters in GeoJSON:

"MongoDB Headquarters" : {
"type": "point",
"coordinates": [-73.986805, 40.7620853]
}

For definitive information on GeoJSON, see the official IETF specification.

A position represents a single place on Earth, and exists in code as an array containing two or three number values:

  • Longitude in the first position (required)

  • Latitude in the second position (required)

  • Elevation in the third position (optional)

Important

Longitude then Latitude

GeoJSON orders coordinates as longitude first and latitude second. This may be surprising as geographic coordinate system conventions generally list latitude first and longitude second. Make sure to check what format any other tools you are working with use. Popular tools such as OpenStreetMap and Google Maps list coordinates as latitude first and longitude second.

Your GeoJSON object's type determines its geometric shape. Geometric shapes are made up of positions.

Here are some common GeoJSON types and how you can specify them with positions:

  • Point: a single position. This could represent the location of a sculpture.

  • LineString: an array of two or more positions, thus forming a series of line segments. This could represent the route of the Great Wall of China.

  • Polygon: an array of positions in which the first and last position are the same, thus enclosing some space. This could represent the land within Vatican City.

To learn more about the shapes you can use in MongoDB, see the GeoJSON manual entry.

To query data stored in the GeoJSON format, add the field containing GeoJSON data to a 2dsphere index. The following snippet creates a 2dsphere index on the location.geo field using the Indexes builder:

collection.createIndex((Indexes.geo2dsphere("location.geo")))

For more information on the Indexes builder, see our guide on the Indexes builder.

You can store geospatial data using x and y coordinates on a two-dimensional Euclidean plane. We refer to coordinates on a two-dimensional plane as "legacy coordinate pairs".

Legacy coordinate pairs have the following structure:

"<field name>" : [ x, y ]

Your field should contain an array of two values in which the first represents the x axis value and the second represents the y axis value.

To query data stored as legacy coordinate pairs, you must add the field containing legacy coordinate pairs to a 2d index. The following snippet creates a 2d index on the coordinates field using the Indexes builder:

collection.createIndex((Indexes.geo2d("coordinates")))

For more information on the Indexes builder, see our guide on the Indexes builder.

For more information on legacy coordinate pairs, see the MongoDB server manual page on legacy coordinate pairs.

Tip

Supported Operators

Spherical (2dsphere) and flat (2d) indexes support some, but not all, of the same query operators. For a full list of operators and their index compatibility, see the manual entry for geospatial queries.

Geospatial queries consist of a query operator and GeoJSON shapes as query parameters.

To query your geospatial data, use one of the following query operators:

  • $near

  • $geoWithin

  • $nearSphere

  • $geoIntersects requires a 2dsphere index

You can specify these query operators in the MongoDB Kotlin driver with the near(), geoWithin(), nearSphere(), and geoIntersects() utility methods of the Filters builder class.

For more information on geospatial query operators, see the manual entry for geospatial queries.

For more information on Filters, see our guide on the Filters builder.

To specify a shape to use in a geospatial query, use the Position, Point, LineString, and Polygon classes of the MongoDB Kotlin driver.

For a full list of the GeoJSON shapes available in the MongoDB Kotlin driver, see the GeoJSON package API Documentation.

The following examples use the MongoDB Atlas sample dataset. You can learn how to set up your own free-tier Atlas cluster and how to load the sample dataset in our quick start guide.

The examples use the theaters collection in the sample_mflix database from the sample dataset.

The examples require the following imports:

import com.mongodb.client.model.geojson.Point
import com.mongodb.client.model.geojson.Polygon
import com.mongodb.client.model.geojson.Position
import com.mongodb.client.model.Filters.near
import com.mongodb.client.model.Filters.geoWithin
import com.mongodb.client.model.Projections.fields
import com.mongodb.client.model.Projections.include
import com.mongodb.client.model.Projections.excludeId

The data is modeled using the following Kotlin data class:

data class Theater(
val theaterId: Int,
val location: Location
) {
data class Location(
val address: Address,
val geo: Point
) {
data class Address(
val street1: String,
val street2: String? = null,
val city: String,
val state: String,
val zipcode: String
)
}
}

The results are modeled using the following Kotlin data class:

data class TheaterResults(
val location: Location
) {
data class Location(
val address: Address
) {
data class Address(
val city: String
)
}
}

The theaters collection already contains a 2dsphere index on the "${Theater::location.name}.${Theater.Location::geo.name}" field.

To search for and return documents from nearest to farthest from a point, use the near() static utility method of the Filters builder class. The near() method constructs a query with the $near query operator.

The following example queries for theaters between 10,000 and 5,000 meters from the Great Lawn of Central Park:

val database = client.getDatabase("sample_mflix")
val collection = database.getCollection<TheaterResults>("theaters")
val centralPark = Point(Position(-73.9667, 40.78))
val query = Filters.near(
"${Theater::location.name}.${Theater.Location::geo.name}", centralPark, 10000.0, 5000.0
)
val projection = Projections.fields(
Projections.include(
"${Theater::location.name}.${Theater.Location::address.name}.${Theater.Location.Address::city.name}"),
Projections.excludeId()
)
val resultsFlow = collection.find(query).projection(projection)
resultsFlow.collect { println(it) }
TheaterResults(location=Location(address=Address(city=Bronx)))
TheaterResults(location=Location(address=Address(city=New York)))
TheaterResults(location=Location(address=Address(city=New York)))
TheaterResults(location=Location(address=Address(city=Long Island City)))
TheaterResults(location=Location(address=Address(city=New York)))
TheaterResults(location=Location(address=Address(city=Secaucus)))
TheaterResults(location=Location(address=Address(city=Jersey City)))
TheaterResults(location=Location(address=Address(city=Elmhurst)))
TheaterResults(location=Location(address=Address(city=Flushing)))
TheaterResults(location=Location(address=Address(city=Flushing)))
TheaterResults(location=Location(address=Address(city=Flushing)))
TheaterResults(location=Location(address=Address(city=Elmhurst)))

Tip

Fun Fact

MongoDB uses the same reference system as GPS satellites to calculate geometries over the Earth.

For more information on the $near operator, see the reference documentation for $near.

For more information on Filters, see our guide on the Filters builder.

To search for geospatial data within a specified shape use the geoWithin() static utility method of the Filters builder class. The geoWithin() method constructs a query with the $geoWithin query operator.

The following example searches for movie theaters in a section of Long Island.

val longIslandTriangle = Polygon(
listOf(
Position(-72.0, 40.0),
Position(-74.0, 41.0),
Position(-72.0, 39.0),
Position(-72.0, 40.0)
)
)
val projection = Projections.fields(
Projections.include(
"${Theater::location.name}.${Theater.Location::address.name}.${Theater.Location.Address::city.name}"),
Projections.excludeId()
)
val geoWithinComparison = Filters.geoWithin(
"${Theater::location.name}.${Theater.Location::geo.name}", longIslandTriangle
)
val resultsFlow = collection.find<TheaterResults>(geoWithinComparison)
.projection(projection)
resultsFlow.collect { println(it) }
TheaterResults(location=Location(address=Address(city=Baldwin))))
TheaterResults(location=Location(address=Address(city=Levittown)))
TheaterResults(location=Location(address=Address(city=Westbury)))
TheaterResults(location=Location(address=Address(city=Mount Vernon)))
TheaterResults(location=Location(address=Address(city=Massapequa)))

The following figure shows the polygon defined by the longIslandTriangle variable and dots representing the locations of the movie theaters returned by our query.

Area of Long Island we are searching for movie theaters

For more information on the $geoWithin operator, see the reference documentation for $geoWithin

For more information on the operators you can use in your query, see the MongoDB server manual page on geospatial query operators

Back

Specify Which Fields to Return