Être valide pour une "requête géospatiale" le "lieu" doit être en longitude, latitude commande et ne peut pas contenir d'autres coordonnées.
Les formats valides sont
{
"location": [long,lat]
}
Ou
{
"location": { "lng": long, "lat": lat }
}
Ou GeoJSON
{
"location": {
"type": "Point",
"coordinates": [long,lat]
}
}
Un autre champ tel que "rayon" est "un autre champ" et ne peut pas faire partie du même tableau.
Idéalement, suivez GeoJSON :
{
"location": {
"type": "Point",
"coordinates": [long,lat]
},
"radius": radius
}
Ce qui, dans la définition du schéma de la mangouste, peut être aussi simple que :
var geoSchema = new Schema({
"location": {
"type": String,
"coordinates": []
},
"radius": Number
});
Lorsque vous traitez des données géospatiales aux coordonnées "globales" réelles, votre index doit être "2dsphere" , que vous définissez éventuellement sur le schéma comme :
geoSchema.index({ "location": "2dsphere" })
Puisqu'il n'y a pas de prise en charge réelle d'un objet "Cercle" dans GeoJSON pris en charge, il est recommandé de conserver un autre champ comme "rayon" et de stocker le "point central".
Le "gros" avantage de GeoJSON par rapport aux autres formats de "paires de coordonnées héritées" est que lors du retour de quelque chose comme une "distance" à partir d'un point via geoNear
ou $geoNear
alors cette "distance" est définie en "mètres" de manière cohérente. C'est également ainsi que vous devez définir toute valeur de "rayon" dans votre stockage pour rester cohérent avec ce résultat.
Avec les autres formats de stockage, le résultat est renvoyé en "radians", pour lequel vous souhaitez probablement convertir et préféreriez ne pas stocker un "rayon" d'un cercle avec cela comme mesure.
La façon dont vous gérez cela est de considérer les données sous cette forme :
{
"locationtype": "circle",
"location": {
"type": "Point",
"coordinates": [1,1]
},
"radius": 4
}
Ensuite, vous utilisez .aggregate()
avec un $geoNear
étape et un $redact
pour filtrer :
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"
}
}}
])
Maintenant, les valeurs utilisées dans l'exemple de requête ne sont qu'un exemple, mais comme indiqué avec les coordonnées de longitude et de latitude "réelles", les attributs de "distance" fonctionnent comme prévu et dans la tolérance de "mètres" comme mentionné précédemment.
Les points ici sont que $geoNear
trouveront tous deux "près" du centre du "cercle" quel que soit le type d'objet. Non seulement cela, mais la commande ici produit une "projection" d'un autre champ dans le document ici nommé dans "distanceField". Ceci représente la distance du cercle "centre" en "mètres".
La deuxième étape ici utilise $redact
puisque c'est un peu comme un $project
et $match
étape de pipeline en un. Contrairement à $match
cet opérateur peut évaluer une condition "logique" en comparant des champs présents dans le document. Dans ce cas, des opérations telles que $$PRUNE
supprimer le document correspondant à la condition "if" où true
et le "supprimer" des résultats ou autrement $$KEEP
le document où la condition était false
.
En un mot, si la "distance" est "supérieure à" puis le "rayon" du "cercle", alors l'objet "se trouve à l'extérieur" du cercle et ne "se coupe pas". Sinon "ça le fait".
Voilà donc les bases de "définir un 'cercle' pour la géométrie dans une collection et de 'l'utiliser' pour obtenir quelque chose comme l'intersection entre un 'Point' ou un autre type d'objet dans le rayon du 'cercle'.