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".