MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Esferas de consulta geoespacial do MongoDB sobrepostas de ponto único


Bem, seria melhor se você pudesse usar um objeto GeoJSON para representar o local, mas a partir de agora o os tipos suportados são realmente limitados portanto, um tipo "Círculo" que seria ideal não é suportado.

O mais próximo que você pode fazer é um "Polygon" aproximando um círculo, mas isso provavelmente é um pouco trabalhoso para construir apenas para essa finalidade de consulta. A outra pegadinha é fazer isso e depois aplicar $geoIntersects é que os resultados não serão "ordenados" pela distância do ponto de consulta. Isso parece ser o contrário do propósito de encontrar a “pizza mais próxima” do ponto de origem.

Felizmente, existe um $geoNear operação adicionada à estrutura de agregação a partir do MongoDB 2.4 e superior. O bom aqui é que permite a "projeção" de um campo de distância nos resultados. Isso permite que você faça a filtragem lógica no servidor para os pontos que estão "dentro do raio" da restrição à distância do ponto de origem. Também permite a classificação no servidor.

Mas você ainda precisará alterar seu esquema para suportar o índice
db.places.insert({
    "name": "Pizza Hut",
    "location": { 
        "type": "Point",
        "coordinates": [
            151.00211262702942,
            -33.81696995135973
        ]
    },
    "radius": 20
})

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

E para a consulta de agregação:
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 } }
])

Basicamente isso diz,

Existem outras opções que você pode passar para $geoNear para refinar o resultado, bem como retornar mais do que os 100 resultados padrão se necessário e basicamente passar outras opções de consulta como um "tipo" ou "nome" ou qualquer outra informação que você tenha no documento.