karthick
karthick

Reputation: 6168

Geonear is not working - mongodb?

I have following sample mongodb document in the collection offers.

Collection : Offers

 {
   "countryCode" : "LU",
   "geoLocation" : [ 
         {
            "lat" : 49.8914114000000026,
            "lng" : 6.0950994999999999
         }
    ]
 },
 {
   "countryCode" : "DE",
   "geoLocation" : [ 
         {
            "lat" : 50.8218536999999984,
            "lng" : 9.0202151000000015
         }
    ]
 }

Requirement:

Fetch the document based on the geolocation which is around 50km radius

What I have tried:

db.getCollection('offers').aggregate([
    {
        $geoNear: {
            near: [6.0950994999999999, 49.8914114000000026],
            distanceField: "geoLocation",
            maxDistance: 50000, //50 km radius
        }
    }
]);

Problem:

It is fetching all the documents instead of searching around 50km.

Any suggestion will be grateful.

Upvotes: 2

Views: 2141

Answers (1)

Blakes Seven
Blakes Seven

Reputation: 50406

Legacy coordinate pairs do not return distances in meters, but in radians instead. Your maxDistance therefore much larger than 50km. See Calculate Distances with Spherical Geometry

But also consider the actual distance being used here:

db.getCollection('offers').aggregate([
    {
        $geoNear: {
            near: [6.0950994999999999, 49.8914114000000026],
            distanceField: "distance"
    }
]);

Returns:

{
    "_id" : ObjectId("55dc0f4b6f07ad5d3ec3b6d0"),
    "countryCode" : "DE",
    "geoLocation" : [
            {
                    "lat" : 50.8218537,
                    "lng" : 9.020215100000001
            }
    ],
    "distance" : 60.588259822017925
}
{
    "_id" : ObjectId("55dc0f4b6f07ad5d3ec3b6cf"),
    "countryCode" : "LU",
    "geoLocation" : [
            {
                    "lat" : 49.8914114,
                    "lng" : 6.0950995
            }
    ],
    "distance" : 61.93733827090219
}

As the "distanceField" is meant to be the field that reports the projected distance from the queried point.

So the start point is that your documents are ot valid for geoSpatial queries. Fix them like this:

First drop all indexes:

db.offers.dropIndexes();

Then fix the fields:

var bulk = db.offers.initializeOrderedBulkOp(),
    count = 0;

db.offers.find({}).forEach(function(doc) { 
  //printjson(doc);

  var tmp = {
    "type": "Point",
    "coordinates": [doc.geoLocation[0].lng,doc.geoLocation[0].lat]
  };
  doc.geoLocation = tmp;
  printjson(doc);

  bulk.find({ "_id": doc._id }).updateOne({
    "$set": { "geoLocation": doc.geoLocation }
  });
  count++;

  if ( count % 1000 == 0 ) {
    bulk.execute();
    bulk = db.offers.initializeOrderedBulkOp();
  }
});

Now the data is represented in a correct GeoJSON format:

{
    "_id" : ObjectId("55dc14856f07ad5d3ec3b6d1"),
    "countryCode" : "LU",
    "geoLocation" : {
            "type" : "Point",
            "coordinates" : [
                    6.0950995,
                    49.8914114
            ]
    }
}
{
    "_id" : ObjectId("55dc14856f07ad5d3ec3b6d2"),
    "countryCode" : "DE",
    "geoLocation" : {
            "type" : "Point",
            "coordinates" : [
                    9.020215100000001,
                    50.8218537
            ]
    }
}

Now create an index as 2dsphere:

db.offers.createIndex({ "geoLocation": "2dsphere" })

Now you are ready to query:

db.offers.aggregate([
    { "$geoNear": {
      "near": {
        "type": "Point",
        "coordinates": [6.0950994999999999, 49.8914114000000026]
      },
      "distanceField": "distance",
      "spherical": true,
      "maxDistance": 50000
    }}
])

Which returns the one document that is "near", or in fact 0 distance:

{
    "_id" : ObjectId("55dc14856f07ad5d3ec3b6d1"),
    "countryCode" : "LU",
    "geoLocation" : {
            "type" : "Point",
            "coordinates" : [
                    6.0950995,
                    49.8914114
            ]
    },
    "distance" : 0
}

Upvotes: 4

Related Questions