Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB sorted geo bounding box

With MongoDB is there a way to perform a bounds query (within a box) and order the results from the center point and have them return with the distance calculation..

I realize doing a near with a radius can provide me with a distance ordered set but I want I'm trying to identify if it is possible within a box not a circle.

like image 588
Nick Avatar asked Apr 03 '12 16:04

Nick


2 Answers

@nick - Marc is incorrect. It is possible. Seem similar question asked here: Mongo Bounding Box Query with Limit

The secret is to combine both a point-radius query with a bounding box one. You get all the benefits of both (sorting, distance, performance).

like image 34
keithhackbarth Avatar answered Nov 22 '22 10:11

keithhackbarth


Unfortunately, this is not possible exactly as you described. As per the "Bounds Queries" section of the "Geospatial Indexing" documentation: "Results [of $within queries] are not sorted by distance" http://www.mongodb.org/display/DOCS/Geospatial+Indexing#GeospatialIndexing-BoundsQueries

There are a few possible work-arounds.

1) You can perform a $within query and have your application calculate the distance of each point returned from the center of the box.

2) You could first perform a $within query, save the points in an array, and then run a $near query combined with an $in [].

For example,

Imagine a box with boundaries [0,0] and [8,8]:

> var box = [ [ 0, 0 ], [ 8, 8 ] ]

and some points:

> db.points.find()
{ "_id" : 1, "name" : "a", "loc" : [ 5, 4 ] }
{ "_id" : 2, "name" : "b", "loc" : [ 4, 2 ] }
{ "_id" : 3, "name" : "c", "loc" : [ 1, 4 ] }
{ "_id" : 4, "name" : "d", "loc" : [ 2, 7 ] }
{ "_id" : 5, "name" : "e", "loc" : [ 7, 7 ] }
{ "_id" : 6, "name" : "f", "loc" : [ 9, 4 ] }

First the $within query is done, and the points that are returned are saved:

> var c = db.points.find({loc:{$within:{"$box":box}}})
> var boxResults = []
> while(c.hasNext()){boxResults.push(c.next().loc)}

Then a $near query is combined with an $in query:

> db.points.find({loc:{$near:[4,4], $in:boxResults}})
{ "_id" : 1, "name" : "a", "loc" : [ 5, 4 ] }
{ "_id" : 2, "name" : "b", "loc" : [ 4, 2 ] }
{ "_id" : 3, "name" : "c", "loc" : [ 1, 4 ] }
{ "_id" : 4, "name" : "d", "loc" : [ 2, 7 ] }
{ "_id" : 5, "name" : "e", "loc" : [ 7, 7 ] }

The above solution was taken from a similar question that was asked on Google Groups: groups.google.com/group/mongodb-user/browse_thread/thread/22d1f0995a628c84/1f2330694a7cf969

Hopefully this will allow you to perform the operation that you need to do.

like image 84
Marc Avatar answered Nov 22 '22 12:11

Marc