MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Wie definiere ich einen Kreis für ein Mongo-DB-Schema?

Gültig für eine "Geodatenabfrage" der "Standort" muss in Längengrad, Breitengrad angegeben werden Reihenfolge und darf keine anderen Koordinaten enthalten.

Gültige Formate sind

 { 
     "location": [long,lat]
 }

Oder

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

Oder GeoJSON

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

Ein anderes Feld wie "Radius" ist "ein anderes Feld" und kann nicht Teil desselben Arrays sein.

Folgen Sie idealerweise GeoJSON:

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

Was in der Mongoose-Schemadefinition so einfach sein kann wie:

var geoSchema = new Schema({
    "location": {
        "type": String,
        "coordinates": []
    },
    "radius": Number
});

Beim Umgang mit Geodaten an echten „Globus“-Koordinaten sollte Ihr Index "2dsphere" , die Sie optional im Schema als :

definieren
geoSchema.index({ "location": "2dsphere" })

Da es in unterstütztem GeoJSON keine tatsächliche Unterstützung für ein „Kreis“-Objekt gibt, wird empfohlen, ein anderes Feld als „Radius“ beizubehalten und den „Mittelpunkt“ zu speichern.

Der „große“ Vorteil von GeoJSON gegenüber den anderen „Legacy-Koordinatenpaaren“-Formaten besteht darin, dass bei der Rückgabe von so etwas wie einer „Entfernung“ von einem Punkt über geoNear oder $geoNear dann wird diese "Entfernung" konsequent in "Metern" definiert. Auf diese Weise sollten Sie auch jeden "Radius"-Wert in Ihrem Speicher definieren, um mit diesem Ergebnis konsistent zu bleiben.

Bei den anderen Speicherformaten wird das Ergebnis dann in "Bogenmaß" zurückgegeben, wofür Sie wahrscheinlich umrechnen möchten und lieber keinen "Radius" eines Kreises damit als Maß speichern möchten.

Die Art und Weise, wie Sie damit umgehen, ist die Betrachtung von Daten in dieser Form:

{
    "locationtype": "circle",
    "location": {
        "type": "Point",
        "coordinates": [1,1]
    },
    "radius": 4
}

Dann verwenden Sie .aggregate() mit einem $geoNear Stufe und ein $redact zu filtern:

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

Nun, die im Abfragebeispiel verwendeten Werte sind nur ein Beispiel, aber wie bereits erwähnt, funktionieren die Attribute "Entfernung" mit "echten" Längen- und Breitengradkoordinaten wie vorgesehen und innerhalb der zuvor erwähnten "Meter"-Toleranz.

Die Punkte hier sind das $geoNear werden beide "in der Nähe" des "Kreis"-Mittelpunktes finden, unabhängig vom Objekttyp. Nicht nur das, sondern der Befehl hier erzeugt eine "Projektion" eines anderen Feldes im Dokument hier, wie in "distanceField" benannt. Dies stellt die Entfernung vom Kreismittelpunkt in "Metern" dar.

Die zweite Stufe hier verwendet $redact da es so etwas wie ein $project und $match Pipelinestufe in einem. Im Gegensatz zu $match Dieser Operator kann eine "logische" Bedingung auswerten, indem er im Dokument vorhandene Felder vergleicht. In diesem Fall Operationen wie $$ PRUNE Entfernen Sie das übereinstimmende Dokument von der „if“-Bedingung, wobei true ist und ihn aus den Ergebnissen „entfernen“ oder anderweitig $$BEHALTEN das Dokument, in dem die Bedingung false war .

Kurz gesagt, wenn "Abstand" "größer als" dann "Radius" des "Kreises" ist, dann "liegt" das Objekt "außerhalb" des Kreises und "schneidet" sich nicht. Andernfalls "es tut".

Das sind also die Grundlagen, um „einen ‚Kreis‘ für die Geometrie in einer Sammlung zu definieren und ihn zu ‚benutzen‘, um so etwas wie den Schnittpunkt zwischen einem ‚Punkt‘ oder einem anderen Objekttyp innerhalb des ‚Kreis‘-Radius zu erreichen.“