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

Como definir um círculo para um esquema mongo db?


Para ser válido para uma "consulta geoespacial" o "local" deve estar em longitude, latitude ordem e não pode conter outras coordenadas.

Os formatos válidos são
 { 
     "location": [long,lat]
 }

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

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

Outro campo como "raio" é "outro campo" e não pode fazer parte da mesma matriz.

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

Que na definição do esquema do mangusto pode ser tão simples quanto:
var geoSchema = new Schema({
    "location": {
        "type": String,
        "coordinates": []
    },
    "radius": Number
});

Ao lidar com dados geoespaciais em coordenadas "globo" reais, seu índice deve ser "2dsphere" , que você define opcionalmente no esquema como :
geoSchema.index({ "location": "2dsphere" })

Como não há suporte real para um objeto "Circle" no GeoJSON suportado, é recomendável manter outro campo como "raio" e armazenar o "ponto central".

A "grande" vantagem do GeoJSON sobre os outros formatos de "pares de coordenadas herdados" é que ao retornar algo como uma "distância" de um ponto via geoNear ou $geoNear então essa "distância" é definida em "metros" de forma consistente. É também assim que você deve definir qualquer valor de "raio" em seu armazenamento para permanecer consistente com esse resultado.

Com os outros formatos de armazenamento, o resultado é retornado em "radianos", para os quais você provavelmente deseja converter e prefere não armazenar um "raio" de um círculo com isso como medida.

A maneira como você lida com isso é, considerando os dados desta forma:
{
    "locationtype": "circle",
    "location": {
        "type": "Point",
        "coordinates": [1,1]
    },
    "radius": 4
}

Então você usa .aggregate() com um $geoNear palco e um $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"
        }
    }}
])

Agora, os valores usados ​​no exemplo de consulta são apenas um exemplo, mas conforme declarado com as coordenadas "reais" de longitude e latitude, os atributos de "distância" funcionam conforme projetado e dentro da tolerância de "metros", conforme mencionado anteriormente.

Os pontos aqui são que $geoNear ambos encontrarão "perto" do ponto central do "círculo", não importa qual seja o tipo de objeto. Não apenas isso, mas o comando aqui está produzindo uma "projeção" de outro campo no documento aqui como nomeado em "distanceField". Isso representa a distância do círculo "centro" em "metros".

O segundo estágio aqui usa $redact já que é como um $project e $match estágio de pipeline em um. Ao contrário de $match este operador pode avaliar uma condição "lógica" comparando os campos presentes no documento. Nesse caso, operações como $$ PODA remova o documento correspondente para a condição "if" onde true e "removê-lo" dos resultados ou $$MANTER o documento onde a condição era false .

Em poucas palavras, se "distância" for "maior que" então "raio" do "círculo", então o objeto "está fora" do círculo e não "se cruza". Caso contrário, "ele faz".

Então, esse é o básico de "definir um 'círculo' para geometria em uma coleção e "usá-lo" para obter algo como a interseção entre um "ponto" ou outro tipo de objeto dentro do raio do "círculo".