MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Sphères de requête géospatiale MongoDB chevauchant un seul point

Eh bien, ce serait mieux si vous pouviez utiliser un objet GeoJSON pour représenter l'emplacement, mais à l'heure actuelle, le les types pris en charge sont en fait limités donc un type "Cercle" qui serait idéal n'est pas supporté.

Le plus proche que vous puissiez faire est un "Polygone" se rapprochant d'un cercle, mais c'est probablement un peu trop de travail à construire juste pour cette requête. L'autre problème est de faire cela, puis d'appliquer $geoIntersects est que les résultats ne seront pas "triés" en fonction de la distance par rapport au point de requête. Cela semble être le contraire de l'objectif de trouver la "pizza la plus proche" du point d'origine.

Heureusement, il existe un $geoNear opération ajoutée au cadre d'agrégation à partir de MongoDB 2.4 et supérieur. La bonne chose ici est qu'il permet la "projection" d'un champ de distance dans les résultats. Cela vous permet ensuite de faire le filtrage logique sur le serveur pour les points qui sont "dans le rayon" contraint à la distance du point d'origine. Il permet également le tri sur le serveur.

Mais vous devrez toujours modifier votre schéma pour prendre en charge l'index

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

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

Et pour la requête d'agrégation :

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 } }
])

En gros, cela dit,

Il existe d'autres options que vous pouvez transmettre à $geoNear afin d'affiner le résultat, ainsi que de renvoyer plus que les 100 résultats par défaut si nécessaire et de transmettre essentiellement d'autres options à la requête telles qu'un "type" ou un "nom" ou toute autre information que vous avez sur le document.