Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find points near LineString in mongodb sorted by distance

Tags:

mongodb

I have an array of points representing a street (black line) and points, representing a places on map (red points). I want to find all the points near the specified street, sorted by distance. I also need to have the ability to specify max distance (blue and green areas). Here is a simple example:

enter image description here

I thought of using the $near operator but it only accepts Point as an input, not LineString.

How mongodb can handle this type of queries?

like image 672
King Julien Avatar asked Sep 25 '13 21:09

King Julien


1 Answers

As you mentioned, Mongo currently doesn't support anything other than Point. Have you come across the concept of a route boxer? 1 It was very popular a few years back on Google Maps. Given the line that you've drawn, find stops that are within dist(x). It was done by creating a series of bounding boxes around each point in the line, and searching for points that fall within the bucket.

I stumbled upon your question after I just realised that Mongo only works with points, which is reasonable I assume.

I already have a few options of how to do it (they expand on what @mnemosyn says in the comment). With the dataset that I'm working on, it's all on the client-side, so I could use the routeboxer, but I would like to implement it server-side for performance reasons. Here are my suggestions:

  1. break the LineString down into its individual coordinate sets, and query for $near using each of those, combine results and extract an unique set. There are algorithms out there for simplifying a complex line, by reducing the number of points, but a simple one is easy to write.

  2. do the same as above, but as a stored procedure/function. I haven't played around with Mongo's stored functions, and I don't know how well they work with drivers, but this could be faster than the first option above as you won't have to do roundtrips, and depending on the machine that your instance(s) of Mongo is(are) hosted, calculations could be faster by microseconds.

  3. Implement the routeboxer approach server-side (has been done in PHP), and then use either of the above 2 to find stops that are $within the resulting bounding boxes. Heck since the routeboxer method returns rectangles, it would be possible to merge all these rectangles into one polygon covering your route, and just do a $within on that. (What @mnemosyn suggested).

  4. EDIT: I thought of this but forgot about it, but it might be possible to achieve some of the above using the aggregation framework.

It's something that I'm going to be working on soon (hopefully), I'll open-source my result(s) based on which I end up going with.

EDIT: I must mention though that 1 and 2 have the flaw that if you have 2 points in a line that are say 2km apart, and you want points that are within 1.8km of your line, you'll obviously miss all the points between that part of your line. The solution is to inject points onto your line when simplifying it (I know, beats the objective of reducing points when adding new ones back in).

The flaw with 3 then is that it won't always be accurate as some points within your polygon are likely to have a distance greater than your limit, though the difference wouldn't be a significant percentage of your limit.

[1] google maps utils routeboxer

like image 184
nevi_me Avatar answered Oct 11 '22 17:10

nevi_me