sql >> Base de Datos >  >> NoSQL >> MongoDB

¿Cómo definir un círculo para un esquema mongo db?

Ser válido para una "consulta geoespacial" la "ubicación" debe estar en longitud, latitud orden y no puede contener ninguna otra coordenada.

Los formatos válidos son

 { 
     "location": [long,lat]
 }

O

 {
    "location": { "lng": long, "lat": lat }
 }

O GeoJSON

 {
     "location": {
         "type": "Point",
         "coordinates": [long,lat]
     }
 }

Otro campo como "radio" es "otro campo" y no puede ser parte de la misma matriz.

Lo ideal es seguir GeoJSON:

 {
     "location": {
         "type": "Point",
         "coordinates": [long,lat]
     },
     "radius": radius
 }

Que en la definición de esquema de mangosta puede ser tan simple como:

var geoSchema = new Schema({
    "location": {
        "type": String,
        "coordinates": []
    },
    "radius": Number
});

Cuando se trata de datos geoespaciales en coordenadas reales de "globo", su índice debe ser "2dsphere" , que puede definir opcionalmente en el esquema como:

geoSchema.index({ "location": "2dsphere" })

Dado que no hay soporte real para un objeto "Círculo" en GeoJSON compatible, se recomienda mantener otro campo como "radio" y almacenar el "punto central".

La "gran" ventaja con GeoJSON sobre los otros formatos de "pares de coordenadas heredados" es que al devolver algo como una "distancia" desde un punto a través de geoNear o $geoNear entonces esa "distancia" se define en "metros" consistentemente. Así es como debe definir cualquier valor de "radio" en su almacenamiento para mantener la coherencia con ese resultado.

Con los otros formatos de almacenamiento, el resultado se devuelve en "radianes", por lo que probablemente desee convertir y preferiría no almacenar un "radio" de un círculo con eso como medida.

La forma de lidiar con esto es, considerando los datos en este formulario:

{
    "locationtype": "circle",
    "location": {
        "type": "Point",
        "coordinates": [1,1]
    },
    "radius": 4
}

Luego usa .aggregate() con un $geoNear escenario y un $redact para filtrar:

db.collection.aggregate([
    // Find points or objects "near" and project the distance
    { "$geoNear": {
        "near": {
            "type": "Point",
            "coordinates": [2,2]
        },
        "distanceField": "distance",
        "query": { "locationType": "circle" }
    }},
    // Logically filter anything outside of the radius
    { "$redact": {
        "$cond": {
            "if": { "$gt": [ "$distance", "$radius" ] },
            "then": "$$PRUNE",
            "else": "$$KEEP"
        }
    }}
])

Ahora, los valores utilizados en el ejemplo de consulta son solo un ejemplo, pero como se indica con las coordenadas de longitud y latitud "reales", los atributos de "distancia" funcionan según lo diseñado y dentro de la tolerancia de "metros" como se mencionó anteriormente.

Los puntos aquí son que $geoNear ambos encontrarán "cerca" del centro del "círculo" puntiagudo sin importar el tipo de objeto. No solo eso, sino que el comando aquí está produciendo una "proyección" de otro campo en el documento aquí como se nombra en "distanceField". Esto representa la distancia desde el "centro" del círculo en "metros".

La segunda etapa aquí usa $redact ya que es algo así como un $project y $match etapa de tubería en uno. A diferencia de $match este operador puede evaluar una condición "lógica" comparando campos presentes en el documento. En este caso, operaciones como $$PRUNE elimine el documento coincidente a la condición "si" donde true y "quitarlo" de los resultados o de lo contrario $$KEEP el documento donde la condición era false .

En pocas palabras, si la "distancia" es "mayor que" entonces el "radio" del "círculo", entonces el objeto "se encuentra fuera" del círculo y no se "cruza". De lo contrario, "lo hace".

Eso es lo básico de "definir un 'círculo' para la geometría en una colección y "usarlo" para lograr algo como la intersección entre un "Punto" u otro tipo de Objeto dentro del radio del "círculo".