Cannot do Collection sort on client side


#1

I’m using Meteor to return a list of Venues that are closest to the user’s geolocation. I have the sort happening correctly from the server but the data is a little jumbled by the time it hits the client. It’s my understanding that another sort needs to happen on the client once the data is received.

I have the following code in publish.js on the server:

Meteor.publish('nearestVenues', function(params){
var limit = !!params ? params.limit : 50;
if (!!params && !!params.coordinates){
	return Venues.find(
		{ 'location.coordinates': 
			{ $near :
        { $geometry :
          { type : "Point" ,
            coordinates : params.coordinates 
          },
         	$maxDistance : 6000,
         	spherical: true
  			} 
  		} 	
		}, {limit: limit});	
} else {
	return Venues.find({}, {limit: limit});
}
});

And the following in a template helper for my view which returns nothing:

Template.VenueList.helpers({
venues: function(){
	return Venues.find(
        { 'location.coordinates': 
          { $near :
            { $geometry :
              { type : "Point" ,
                coordinates : Session.get('currentUserCoords') 
              },
              $maxDistance : 6000,
              spherical: true
            } 
          }   
        }, {limit: 10})
	// return Venues.find({}, {limit: 5, sort: {_id: -1, createdAt: -1}});
}

Note: the commented out code at the bottom of the helper does in fact work so I know this is the correct place to do a client-side sort. So, how do I do a client side sort when the information is sorted by a Mongo geospatial method? There has to be a way to sort geolocation data from closest to farthest from a location— what am I missing here?


#2

Could it be that the client-side, Minimongo, impl of the Mongo API simply does not handle geolocation sorting?
If that really were the case the solutions might be to work with a Meteor method instead of a publication (losing out on the reactivity), finding another library that provides geolocation sorting in the browser, or, if that’s somehow possible, adding a simple “geolocationRank” field on the server to the published fields so the client can just sort on that and doesn’t need to know about the specifics of distance of coordinates on a sphere. In the last case I think there’d still have to be some manual publication management, or maybe there’s some package that provides extending collection items on the server before publication.


#3

It is very possible Minimongo can’t handle geolocation sorting or many $methods on the client. The problem is I can’t seem to find a source of truth on what is possible in Minimongo. Are there docs for Minimongo anywhere or does it handle a baseline of methods and everybody knows it?


#4

WIth just a very quick look at the Meteor source it looks like it may be properly implemented and supported – check out minimongo core package source, search for $near.
I have never done any geolocation queries & sorting, so I’m not the best person to guide you on this. But I would do these things, in order, if I wanted to solve this:
Make absolutely sure that on the server side you get the query and the ordering fully correct. If that proves a little hard, get the query correct without Meteor, so with just Mongo shell (meteor mongo if it’s not a standalone MongoDB). And only then move on to checking things out on the client.

Because it does seem like a) geo-queries are implemented and support client-side and b) Meteor/Minimongo would complain if you asked it to do anything it cannot do.
So most likely you just have a bug somewhere in your geo query :slight_smile:


#5

@seeekr It looks like I found a bug… gasp within Minimongo! https://github.com/meteor/meteor/issues/2077


#6

Great! (I think?) So does that mean you were / will be able to work around the issue?


#7

Wellllll … sorta @seeekr, this has been an open issue for a couple of months now. I have made progress though but I’m not sure it’s working 100%. Check this out:

Bushwick - Brooklyn Public Library 7.64 blocks
HERBERT VON KING 0.7207892 mi
Herbert Von King Park 0.74067304 mi
Dekalb - Brooklyn Public Library 0.66238042 mi
Marcy - Brooklyn Public Library 0.79286812 mi
Macon - Brooklyn Public Library 1.13524299 mi
Leonard - Brooklyn Public Library 1.09671805 mi
McCarren Park 1.52297787 mi
McCarren Park 1.53664801 mi
McCarren Park 1.55839596 mi
McCarren Park 1.60189186 mi
McCarren Park 1.61866885 mi
Brower Park - Brooklyn Public Library 1.6963401 mi
ST JOHNS REC CNTR 1.74107874 mi
ST JOHNS REC CNTR 1.7460497 mi
ST JOHNS REC CNTR 1.75661299 mi
ST JOHNS REC CNTR 1.75599162 mi
ST JOHNS REC CNTR 1.7584771 mi
ST JOHNS REC CNTR 1.75909847 mi
ST JOHNS REC CNTR 1.76096258 mi
ST JOHNS REC CNTR 1.76220532 mi
ST JOHNS REC CNTR 1.76406943 mi
ST JOHNS REC CNTR 1.76593354 mi
McCarren Park 1.70938887 mi
ST JOHNS REC CNTR 1.78643875 mi
Greenpoint - Brooklyn Public Library 1.95172317 mi
Eastern Parkway - Brooklyn Public Library 2.1312991 mi
Crown Heights - Brooklyn Public Library 2.6470362 mi
WINGATE PARK 2.81853432 mi
WINGATE PARK 2.81853432 mi
WINGATE PARK 2.85768063 mi
WINGATE PARK 2.85768063 mi
WINGATE PARK 2.89620557 mi
WINGATE PARK 2.89620557 mi
COURT SQ. - LONG ISLAND CITY 3.28456182 mi
Court Square 3.32308676 mi

So here’s results from my query now. It’s almost perfect! Nevermind the repeating values, these are actual free NYC hotspots for WIFI, they just have repeaters everywhere. I’ll figure that UX issue out later… the point is this: see the BOLD in those results near the top? they don’t go in perfect order. But the remaining results do.

Here is my client side template helper which is almost working perfectly:

Template.VenueList.helpers({
venues: function(){
	return Venues.find(
  { 'location.coordinates': 
    { 
      $near : Session.get('currentUserCoords') ? Session.get('currentUserCoords') :      Meteor.settings.public.Defaults.defaultUserCoords
    }   
  }, {
    limit: Session.get('defaultVenueLimit') ? Session.get('defaultVenueLimit') : Meteor.settings.public.Defaults.defaultVenueLimit
  }
)
});