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

Mongoose-Aggregation mit Geonear

Sie können dafür das Aggregations-Framework verwenden, und es gibt keine wirklichen Nachteile, da die Vorgänge im Wesentlichen gleich sind.

Aber während der Mungo .find() -Methode hat derzeit ein Problem mit $nearSphere Operator, der äquivalent ist, können Sie immer das Raw-Knotentreiber-Verbindungsobjekt abrufen und Ihre Abfrage ausführen.

Sie müssen Dinge wie "Bevölkerung" nicht einmal wegwerfen, wenn Sie bereit sind, ein wenig Handhabung zu implementieren.

Hier sind meine Testdaten:

{ 
    "_id" : "P1",
    "amenity" : "restaurant", 
    "shape" : { 
        "type" : "Point", 
        "coordinates" : [ 2, 2 ] 
    }
}
{ 
    "_id" : "P3",
    "amenity" : "police",
    "shape" : { 
        "type" : "Point", 
        "coordinates" : [ 4, 2 ]
    }
}
{ 
    "_id" : "P4",
    "amenity" : "police",
    "shape" : {
        "type" : "Point",
        "coordinates" : [ 4, 4 ]
    }
}
{ 
    "_id" : "P2",
    "amenity" : "restaurant",
    "shape" : { 
        "type" : "Point",
        "coordinates" : [ 2, 4 ]
    }, 
    "info" : ObjectId("539b90543249ff8d18e863fb")
}

Und der grundlegende Code, um dies zu handhaben:

var mongoose = require('mongoose'),
    async = require('async'),
    Schema = mongoose.Schema;


mongoose.connect('mongodb://localhost');

var infoSchema = new Schema({
  "description": String
});

var shapeSchema = new Schema({
  "_id": String,
  "amenity": String,
  "shape": {
    "type": { "type": String },
    "coordinates": []
  },
  "info": { "type": Schema.Types.ObjectId, "ref": "Info" }
});

var Shape = mongoose.model( "Shape", shapeSchema );
var Info = mongoose.model( "Info", infoSchema );


Shape.collection.find(
  {
    "shape": {
      "$nearSphere": {
        "$geometry": {
          "type": "Point",
          "coordinates": [ 2, 4 ]
        }
      }
    }
  },
  {
    "skip": 0, "limit": 2
  },
  function(err,cursor) {

    cursor.toArray(function(err,shapes) {

      Shape.populate( shapes, { path: "info" }, function(err,docs) {
        if (err) throw err;

        console.log( JSON.stringify( docs, undefined, 4 ) );
      });

    });

  }
);

Hier haben Sie also die Verwendung sowohl des Überspringens und begrenzen Operationen am Cursor, ließ einen Cursor zurückgeben und verarbeitete die Dokumente sogar zurück in "Mongoose-Dokumente", sodass Sie Funktionen wie .populate() aufrufen können auf ihnen.

Ich würde die aktuelle Ausgabe mit $nearSphere relativ bald behoben werden.

Oder verwenden Sie stattdessen Aggregat:

Shape.aggregate(
  [
    { "$geoNear": {
        "near": {
          "type": "Point",
          "coordinates": [ 2, 4 ]
        },
        "spherical": true,
        "distanceField": "dis"
    }},
    { "$skip": 0 },
    { "$limit": 2 }

  ],
  function(err,shapes) {
    if (err) throw err;
    //console.log( shapes );

    shapes = shapes.map(function(x) {
      delete x.dis;
      return new Shape( x );
    });

    Shape.populate( shapes, { path: "info" }, function(err,docs) {
      if (err) throw err;

      console.log( JSON.stringify( docs, undefined, 4 ) );
    });

  }
);

Wo Sie dieselben Dinge tun können, wie z. B. .populate() verwenden . Beide Fälle geben Ergebnisse wie dieses mit übereinstimmendem "ausgefüllten" Feld zurück:

{
    "_id": "P2",
    "amenity": "restaurant",
    "info": {
        "_id": "539b90543249ff8d18e863fb",
        "description": "Jamies Restaurant",
        "__v": 0
    },
    "shape": {
        "type": "Point",
        "coordinates": [
            2,
            4
        ]
    }
},
{
    "info": null,
    "_id": "P4",
    "amenity": "police",
    "shape": {
        "type": "Point",
        "coordinates": [
            4,
            4
        ]
    }
}

Wenn Sie die sphärische Geometrieberechnung nicht benötigen, dann natürlich $near funktioniert einwandfrei mit der Mongoose-Implementierung von .find()