2015-08-25 35 views
6

Ich versuche die Länge/Breite eines Ortes in meinem Benutzermodell zu speichern und abzufragen mit $geoNear. Ich habe mir fast jede Seite angesehen, die ich zu diesem Thema finden konnte, aber ich bin mir nicht sicher, wie ich 1) das Modell entsprechend erstellen und wie ich es abfragen kann.Erstellen und Finden von GeoLocation in Mungo

hier ist der Teil meines Modell:

loc: { 
     //type: 'Point', // see 1 
     //type: String, // see 2 
     coordinates: [Number], 
     index: '2dsphere' // see 3 
    }, 

@ 1: die Art der Dokumentation nach ‚Punkt‘ sein muss, wenn ich einen Punkt speichern wollen, aber es wirft

TypeError: Undefined type `Point` at `loc` 
    Did you try nesting Schemas? You can only nest using refs or arrays. 

die macht Sinn, da ich denke, es sollte ein String

@ 2 sein: das wirft nicht sofort einen Fehler, aber wenn ich versuche, einen Benutzer zu speichern, bekomme ich:

name: 'ValidationError', 
    errors: 
    { loc: 
     { [CastError: Cast to String failed for value "[object Object]" at path "loc"] 

@ 3: Wenn ich den Index wie das erstellen möchten erhalte ich die Fehlermeldung:

TypeError: Undefined type `2dsphere` at `loc.index` 
    Did you try nesting Schemas? You can only nest using refs or arrays. 

so habe ich versucht, den Index zu speichern, was fühlte sich ein wenig besser geeignet für mich wie folgt aus:

userSchema.index({'loc': '2dsphere'}); 

, die die folgenden Fehler auslöst, wenn ich versuche, einen neuen Benutzer zu speichern:

- { [MongoError: Can't extract geo keys from object, malformed geometry?:{ coordinates: [ -73.97, 40.77 ] }] 
    name: 'MongoError', 
    message: 'Can\'t extract geo keys from object, malformed geometry?:{ coordinates: [ -73.97, 40.77 ] }', 
    ok: 1, 
    n: 0, 
    code: 16572, 
    errmsg: 'Can\'t extract geo keys from object, malformed geometry?:{ coordinates: [ -73.97, 40.77 ] }', 
    writeConcernError: 
    { code: 16572, 
    errmsg: 'Can\'t extract geo keys from object, malformed geometry?:{ coordinates: [ -73.97, 40.77 ] }' } } 
MongoError: Can't extract geo keys from object, malformed geometry?:{ coordinates: [ -73.97, 40.77 ] } 

Als ich mein Modell in der Datenbank zu einem $geoNear Befehl, den ich meinen Benutzer wie folgt aktualisiert aktualisiert:

loc: {coordinates: [-73.97, 40.77]} 

und erfolgreich wie diese Abfrage könnte:

mongoose.model('users').db.db.command({ 
    "geoNear": users, 
    "near": [ 
     <latitude>, 
     <longitude> 
    ], 
    "spherical": true, 
    "distanceMultiplier": 6378.1, // multiplier for kilometres 
    "maxDistance": 100/6378.1, // every user within 100 km 
    "query": { } 

(I verwendet db.command seit dem, was ich gelesen habe $geoNear ist nicht verfügbar bei der Verwendung find())

Alles, was ich bisher versucht habe Ich bin nirgendwo, also meine Frage ist jetzt:

  • Wie sollte mein Mungo-Modell aussehen?
  • wie kann ich speichere einen Benutzer mit seinem Standort in meiner Datenbank

Jede Hilfe wäre sehr willkommen!

Antwort

22

Wenn Sie ein Schema wollen GeoJSON unterstützen, die Sie müssen zuerst das richtig konstruieren:

var userSchema = new Schema({ 
    loc: { 
     type: { type: String }, 
     coordinates: [Number], 
    } 
}); 

die dafür sorgt, gibt es keine Verwechslung mit dem „Typ“ Schlüsselwort des Schemas Defintition.Wenn Sie wirklich die ganze Bandbreite der GeoJSON Typen unterstützen wollen, dann können Sie das ein bisschen lockerer machen:

var userSchema = new Schema({ 
    loc: { 
     type: { type: String }, 
     coordinates: [] 
    } 
}); 

Als nächstes wollen Sie einen Index auf die shema binden:

userSchema.index({ "loc": "2dsphere" }); 

Dann natürlich definieren Sie ein Modell und speichern Dinge richtig:

var User = mongoose.model("User", userSchema); 

var user = new User({ 
    "loc": { 
     "type": "Point", 
     "coordinates": [-73.97, 40.77] 
    } 
}); 

Anbetracht dessen, dass Ihre Daten dann lat in Länge sein muss itude Reihenfolge wie von GeoJSON und alle MongoDB Geospatial-Abfrage-Formulare unterstützt.

Als nächstes, anstatt in obskuren Verwendungen von Datenbankbefehlen direkt auf der Raw-Treiber-Methode zu graben, verwenden Sie stattdessen Dinge, die direkt unterstützt werden, und besser. Wie $geoNear für die .aggregate() Methode:

User.aggregate(
    [ 
     { "$geoNear": { 
      "near": { 
       "type": "Point", 
       "coordinates": [<long>,<lat>] 
      }, 
      "distanceField": "distance", 
      "spherical": true, 
      "maxDistance": 10000 
     }} 
    ], 
    function(err,results) { 

    } 
) 

Und jetzt, da die Daten GeoJSON ist, werden die Abstände bereits in Meter umgerechnet, so gibt es keine Notwendigkeit, andere Umbauarbeiten zu tun.

Beachten Sie auch, dass Sie damit herumgespielt haben, wenn Sie die Sammlung nicht fallen lassen, wird ein Index, den Sie ausprobiert haben, immer noch da sein, und das wird wahrscheinlich Probleme verursachen.

Sie können alle Indizes aus der Sammlung fallen in der mongodb Schale mit Leichtigkeit:

db.users.dropIndexes(); 

Oder weil Sie wahrscheinlich einige Daten Re-Shaping tun müssen, und dann die Sammlung fallen und wieder starten:

db.users.drop(); 

Richten Sie die Dinge richtig ein und Sie werden keine Probleme haben.

+0

danke für Ihre Hilfe! Das Speichern eines Benutzers funktioniert jetzt einwandfrei. Ich schaue mir auch deine "Aggregat" -Implementierung an, sehe viel schöner aus als die Art von Hack, die ich vorher hatte. – Markus

+1

Danke für diese Info, benutze bitte "sphärisch" statt "spärisch" in deinem geo Abfrage. –