Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /
Datos del modelo

Datos geoespaciales - Kotlin SDK

Novedades en la versión 1.11.0.

Los datos geoespaciales, o "geodatos", especifican puntos y objetos geométricos en la superficie de la Tierra.

Kotlin SDK version 1.11.0 and later adds experimental geospatial APIs that support querying with geospatial data. These queries can check whether a given point is contained within a shape. For example, you can find all coffee shops within 15 km of a specified point.

Changed in version 1.13.0: Geospatial data supported in Atlas Device Sync

Kotlin SDK version 1.13.0 and later adds support for geospatial data in Atlas Device Sync. This allows you to subscribe to geospatial queries in a synced realm. If you try to subscribe to a geospatial query with an older version of the SDK, you will receive a server error with a compensating write.

For more information about managing your Sync subscriptions, refer to Manage Sync Subscriptions - Kotlin SDK.

Para obtener más información sobre cómo consultar datos geoespaciales con Device Sync, consulte Datos geoespaciales en la documentación de App Services.

El SDK de Kotlin admite consultas geoespaciales utilizando los siguientes tipos de datos:

  • GeoPoint

  • GeoCírculo

  • GeoBox

  • GeoPolígono

El SDK proporciona estos tipos de datos geoespaciales para simplificar la consulta de datos geoespaciales. No se pueden guardar estos tipos de datos directamente.

For information on how to persist geospatial data, refer to the Persist Geospatial Data section on this page.

Un GeoPunto define una ubicación específica en la superficie terrestre. Todos los tipos de datos geoespaciales utilizan GeoPoints para definir su ubicación.

Un GeoCircle define un círculo en la superficie de la Tierra. Defines un GeoCircle proporcionando un GeoPoint para el centro del círculo y un objeto Distance para especificar el radio del círculo.

Nota

You can define the radius in kilometers, miles, degrees, or radians.

El siguiente ejemplo crea 2 círculos:

val circle1 = GeoCircle.create(
center = GeoPoint.create(47.8, -122.6),
radius = Distance.fromKilometers(44.4)
)
val circle2 = GeoCircle.create(
center = GeoPoint.create(47.3, -121.9),
radius = Distance.fromDegrees(0.25)
)
Two GeoCircles
haga clic para ampliar

Un GeoBox define un rectángulo sobre la superficie terrestre. Definis el rectángulo especificando la esquina inferior izquierda (sudoeste) y la esquina superior derecha (noreste).

El siguiente ejemplo crea 2 cajas:

val box1 = GeoBox.create(
bottomLeft = GeoPoint.create(47.3, -122.7),
topRight = GeoPoint.create(48.1, -122.1)
)
val box2 = GeoBox.create(
bottomLeft = GeoPoint.create(47.5, -122.4),
topRight = GeoPoint.create(47.9, -121.8)
)
2 GeoBoxes
haga clic para ampliar

Un GeoPolígono define un polígono en la superficie de la Tierra.

Because a polygon is a closed shape, you must provide a minimum of 4 points: 3 points to define the polygon's shape and a fourth to close the shape.

Importante

The fourth point in a polygon must be the same as the first point.

También puedes excluir áreas dentro de un polígono definiendo uno o más «agujeros». Un agujero es otro polígono cuyas fronteras encajan completamente dentro del polígono exterior. Los agujeros también pueden anidarse unos dentro de otros. Una ubicación se considera dentro del polígono si está incluida en un número impar de anillos.

The following example creates 3 polygons:

  • A basic polygon with 5 points

  • The same polygon with a single hole

  • El mismo polígono con dos agujeros.

// Create a basic polygon
val basicPolygon = GeoPolygon.create(
listOf(
GeoPoint.create(48.0, -122.8),
GeoPoint.create(48.2, -121.8),
GeoPoint.create(47.6, -121.6),
GeoPoint.create(47.0, -122.0),
GeoPoint.create(47.2, -122.6),
GeoPoint.create(48.0, -122.8)
)
)
// Create a polygon with a single hole
val outerRing = listOf(
GeoPoint.create(48.0, -122.8),
GeoPoint.create(48.2, -121.8),
GeoPoint.create(47.6, -121.6),
GeoPoint.create(47.0, -122.0),
GeoPoint.create(47.2, -122.6),
GeoPoint.create(48.0, -122.8)
)
val hole1 = listOf(
GeoPoint.create(47.8, -122.6),
GeoPoint.create(47.7, -122.2),
GeoPoint.create(47.4, -122.6),
GeoPoint.create(47.6, -122.5),
GeoPoint.create(47.8, -122.6)
)
val polygonWithOneHole = GeoPolygon.create(outerRing, hole1)
// Add a second hole to the polygon
val hole2 = listOf(
GeoPoint.create(47.55, -122.05),
GeoPoint.create(47.5, -121.9),
GeoPoint.create(47.3, -122.1),
GeoPoint.create(47.55, -122.05)
)
val polygonWithTwoHoles = GeoPolygon.create(outerRing, hole1, hole2)
3 GeoPolygons
haga clic para ampliar

Importante

Cannot Persist Geospatial Data Types

Actualmente, solo se pueden persistir datos geoespaciales. Los tipos de datos geoespaciales no pueden persistirse directamente. Por ejemplo, no se puede declarar una propiedad que sea del tipo GeoBox.

Estos tipos solo pueden utilizarse como argumentos para consultas geoespaciales.

Si desea conservar datos geoespaciales, deben cumplir con la especificación GeoJSON.

To do this with the Kotlin SDK, you can create a GeoJSON-compatible embedded class that you can then use in your data model.

Para crear una clase que se ajuste a la especificación GeoJSON, debes:

  1. Crea un objeto de reino incrustado (una clase que hereda de EmbeddedRealmObject).

  2. Como mínimo, agregue los dos campos requeridos por la especificación GeoJSON:

    • Un campo de tipo String propiedad que se asigna a una propiedad type con el valor de "Point": var type: String = "Point"

    • A field of type RealmList<Double> that maps to a coordinates property in the realm schema containing a latitude/longitude pair: var coordinates: RealmList<Double> = realmListOf()

The following example shows an embedded class named CustomGeoPoint that is used to persist geospatial data:

class CustomGeoPoint : EmbeddedRealmObject {
constructor(latitude: Double, longitude: Double) {
coordinates.apply {
add(longitude)
add(latitude)
}
}
// Empty constructor required by Realm
constructor() : this(0.0, 0.0)
// Name and type required by Realm
var coordinates: RealmList<Double> = realmListOf()
// Name, type, and value required by Realm
private var type: String = "Point"
@Ignore
var latitude: Double
get() = coordinates[1]
set(value) {
coordinates[1] = value
}
@Ignore
var longitude: Double
get() = coordinates[0]
set(value) {
coordinates[0] = value
}
}

Use the customGeoPoint class in your realm model, as shown in the following example:

class Company : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId()
var location: CustomGeoPoint? = null
}

You can then add instances of your class to the realm:

realm.writeBlocking {
copyToRealm(
Company().apply {
location = CustomGeoPoint(47.68, -122.35)
}
)
copyToRealm(
Company().apply {
location = CustomGeoPoint(47.9, -121.85)
}
)
}

La siguiente imagen muestra los resultados de crear estos dos objetos Company :

2 GeoPoints
haga clic para ampliar

To query against geospatial data, you can use the GEOWITHIN operator with RQL. This method takes the coordinates property of an embedded object and checks if that point is contained within the geospatial shape for that object.

El formato para consultar datos geoespaciales es el mismo, independientemente de la forma de la región de geodatos.

Importante

No se pueden utilizar consultas parametrizadas con datos geoespaciales.

The following examples show querying against various shapes to return a list of companies within the shape.

val companiesInLargeCircle =
realm.query<Company>("location GEOWITHIN $circle1").find()
println("Companies in large circle: ${companiesInLargeCircle.size}")
val companiesInSmallCircle =
realm.query<Company>("location GEOWITHIN $circle2").find()
println("Companies in small circle: ${companiesInSmallCircle.size}")
Companies in large circle: 1
Companies in small circle: 0
Ejemplo de consulta de un GeoCircle
haga clic para ampliar
val companiesInLargeBox =
realm.query<Company>("location GEOWITHIN $box1").find()
println("Companies in large box: ${companiesInLargeBox.size}")
val companiesInSmallBox =
realm.query<Company>("location GEOWITHIN $box2").find()
println("Companies in small box: ${companiesInSmallBox.size}")
Companies in large box: 1
Companies in small box: 2
Querying a GeoBox example
val companiesInBasicPolygon =
realm.query<Company>("location GEOWITHIN $basicPolygon").find()
println("Companies in basic polygon: ${companiesInBasicPolygon.size}")
val companiesInPolygonWithHoles =
realm.query<Company>("location GEOWITHIN $polygonWithTwoHoles").find()
println("Companies in polygon with holes: ${companiesInPolygonWithHoles.size}")
Companies in basic polygon: 2
Companies in polygon with holes: 1
Querying a GeoPolygon example
haga clic para ampliar

Volver

Relaciones

En esta página