Automattic / mongoose

MongoDB object modeling designed to work in an asynchronous environment.
https://mongoosejs.com
MIT License
26.98k stars 3.85k forks source link

query.within() not working with geoJson #2092

Closed cultofmetatron closed 10 years ago

cultofmetatron commented 10 years ago

I'm creating some methods to simplify certain geoqueries in our new tracking application and I'm having no luck getting geojson to work as query parameters.

for instance, given a method

//takes a timestamp and returns the location of all carriers given since that timestamp
//params:
//  from:[REQUIRED] timestamp required date object from this data
//  to: optional timestamp to clause
//  bounds: optional bounding area in geojson for scoping down timestamps
beaconSchema.static('since', function(params) {
    var query = this.distinct('carrier_id').find();
    query = (params.from) ? query.where('ts').gte(params.from) : query;
    query = (params.to)   ? query.lte(params.to)               : query;
    //now search for geolocations
    if (params.bounds) {
      query = query.where('loc').within(params.bounds);
    }
    return query;
});

I'm finding in my test that using a geoJson object in my within clause causes an error in the code but using the mongoose specific "polygon": [[] [] []] style works just fine.

Promise.all([
      db.models.Beacon.logBeacon('9c69a880-df98-11e3-8b68-0800200c9a66', [], 37.8046198, -122.2970253), //1526 5th stOakland
      db.models.Beacon.logBeacon('9c69a880-df98-11e3-8b68-0800200c9a66', [], 37.7774232, -122.3958836), //1 bluxome rd, san fran
      db.models.Beacon.logBeacon('9c69a880-df98-11e3-8b68-0800200c9a66', [], 37.7848734, -122.406361), // powell st station
    ])
    .then(function() {
      return db.models.Beacon.since({
        /*
        //this works
        bounds: {
          "polygon": [
            [-122.523566, 37.808835],
            [-122.390786, 37.814938],
            [-122.368384, 37.763184],
            [-122.528716, 37.744454],
            [-122.523566, 37.808835]
          ]
        }
        */
        //this does not work, throws [Can't canonicalize query: BadValue bad geo query]
        bounds: {
          type: "Polygon",
          coordinates: [
            [-122.523566, 37.808835],
            [-122.390786, 37.814938],
            [-122.368384, 37.763184],
            [-122.528716, 37.744454],
            [-122.523566, 37.808835]
          ]
        }

        //bounds: boundry
      }).exec();
    })
    .then(function(result) {
      console.log(result);
      done();
    })

is this a known issue? I'm using mongo 2.6.1 with mongoose 3.8.9

PatrickJS commented 10 years ago

:+1:

MehulATL commented 10 years ago

:+1:

vkarpov15 commented 10 years ago

Thanks for pointing this out, I'm on it.

vkarpov15 commented 10 years ago

@cultofmetatron @gdi2290 @Mayho this isn't actually an issue with mongoose. If you take a look at the docs for MongoDB's $geoWithin operator, you'll see that you need another set of square braces. This is because $geoWithin provides an interface for dealing with polygons with multiple rings. For example, the following code:

var mongoose = require("mongoose");

var Schema = mongoose.Schema;

var Car = mongoose.model("Car", {
  loc: { lat: Number, lng: Number }
});

mongoose.connect("mongodb://localhost/2092");

var db = mongoose.connection;

db.on("open", function() {
  Car.
    find().
    where('loc').
    within({
      type: 'Polygon',
      coordinates: [
        [
          [-122.523566, 37.808835],
          [-122.390786, 37.814938],
          [-122.368384, 37.763184],
          [-122.528716, 37.744454],
          [-122.523566, 37.808835]
        ]
      ]
    }).
    exec(function(error, cars) {
      console.log(error);
    });
});

works as expected. I agree this is a bit of a gotcha, but I think this qualifies as "works as designed", although I'd be happy to hear arguments to the contrary.