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

Esferas de consulta geoespacial de MongoDB que se superponen en un solo punto

Bueno, sería mejor si pudiera usar un objeto GeoJSON para representar la ubicación, pero a partir de ahora los tipos admitidos son realmente limitados por lo tanto, no se admite un tipo "Círculo" que sería ideal.

Lo más cercano que podría hacer es un "Polígono" que se aproxime a un círculo, pero esto probablemente sea demasiado trabajo para construir solo para este propósito de consulta. El otro problema es hacer esto y luego aplicar $geoIntersects es que los resultados no serán "ordenados" por la distancia desde el punto de consulta. Eso parece ser lo opuesto al propósito de encontrar la "pizza más cercana" al punto de origen.

Afortunadamente hay un $geoNear operación agregada al marco de agregación a partir de MongoDB 2.4 y superior. Lo bueno aquí es que permite la "proyección" de un campo de distancia en los resultados. Esto le permite realizar el filtrado lógico en el servidor a aquellos puntos que están "dentro del radio" restringido a la distancia desde el punto de origen. También permite ordenar en el servidor.

Pero aún necesitará cambiar su esquema para admitir el índice

db.places.insert({
    "name": "Pizza Hut",
    "location": { 
        "type": "Point",
        "coordinates": [
            151.00211262702942,
            -33.81696995135973
        ]
    },
    "radius": 20
})

db.places.ensureIndex({ "location": "2dsphere" })

Y para la consulta de agregación:

db.places.aggregate([

    // Query and project distance
    { "$geoNear": {
        "near": { 
            "type": "Point",
            "coordinates": [ 
                150.92094898223877,
                -33.77654333272719
            ]
        },
        "distanceField": "distance",
        "distanceMultiplier": 0.001,
        "maxDistance": 100000,
        "spherical": true
    }},

    // Calculate if distance is within delivery sphere
    { "$project": {
         "name": 1,
         "location": 1,
         "radius": 1,
         "distance": 1,
         "within": { "$gt": [ "$radius", "$distance" ] }
    }},

    // Filter any false results
    { "$match": { "within": true } },

    // Sort by shortest distance from origin
    { "$sort": { "distance": -1 } }
])

Básicamente esto dice,

Hay otras opciones que puede pasar a $geoNear para refinar el resultado, así como devolver más de los 100 resultados predeterminados si es necesario y básicamente pasar otras opciones para consultar como un "tipo" o "nombre" o cualquier otra información que tenga en el documento.