3

What I'm trying to do is to sort mongoid geo_near(or within_circle) max_distance results by distance because I don't know why but it doesn't do that by default.

I have mongoid_geospatial, mongoid_spacial and rgeo in my Rails gem file. I know mongoid_spacial has this ability but I could not use it and it caused problems with gmaps4rails.

I'm trying on mongoid_geospatial(which uses mongoid libraries) with no success and I could not find any resource except this one https://stackoverflow.com/questions/18633636/mongodb-aggregate-geonear-maxdistance but I don't know how to convert mongo that to mongoid.

Any one had an experience on sorting geo_near or within_circle in mongoid? Any help will be greatly appreciated.

The code in my Controller

      searchterm = session[:categoryid].to_s
      radius = session[:distance].to_f / 10       
      @places = Provider.all.where(:category.to_s => /.*#{searchterm}.*/)
      .geo_near([ session[:latitude].to_f,session[:longitude].to_f ]).max_distance(radius)    

      #@places = Provider.all.where(:category.to_s => /.*#{searchterm}.*/)
      #.within_circle(location: [[ session[:latitude].to_f,session[:longitude].to_f ], radius ])      
      #.sort(:servicescore.desc).sort(:pricescore.desc)

The code in my model

include Mongoid::Document 
  include Mongoid::Timestamps
  include Mongoid::Paranoia
  include Mongoid::Geospatial
  include Mongoid::MultiParameterAttributes
  include Mongoid::Slug
  include Mongoid::Spacial::Document  
  include Gmaps4rails::ActsAsGmappable
  acts_as_gmappable :lat => 'latitude', :lon => 'longitude', :process_geocoding => true,
                    :check_process => :prevent_geocoding,
                    :address => "business_address"
  field :location, :type => Point
  spatial_index :location
  field :officialname
  field :business_description
  field :category#, :type => Array
  field :business_type
  field :tax_office
  field :tax_number
  field :pin  
  field :business_phone
  field :web_site
  field :business_address   
  field :latitude
  field :longitude

-------------------------------------------------------------------------------

-------------------------------------------------------------------------------

EDIT ON QUESTION

map

I've tried almost anything related without success. Read mongo and mongoid geo_near documentation. It does comment on storing location [lon, lat] order. I've tried both [lon, lat] and [lat, long] both when saving the provider and for the center location. Tried spherical geo_near and within_circle too. Still without success. Geo_near returns my results incorrectly ordered as seen on the map above and on the list below. There should be something I'm missing but can't find it.

The red parts are the "geo_near_distance" output results, the list is sorted according to those but they are wrong as seen on the map. The green calculation is jquery code I've been using that returns correct distances(though cannot use in controller).

There should be something I'm missing. Can anyone spot that?

results

here is my latest code:

Provider.rb

  field :location, :type => Array  # [lat,lng]
  index({ location: "2d" }, { min: -180, max: 180 })
  spatial_index :location  

Providers_controller

  center = [session[:longitude].to_f, session[:latitude].to_f]
  radious = 100
  searchterm = session[:categoryid].to_s
  radius = session[:distance].to_f / 10     
  @places = Provider.all.where(:category.to_s => /.*#{searchterm}.*/)
  .geo_near(center).max_distance(radious)#.spherical
  #.near(location: center)
  #.within_circle( location: [center,radius] )
  #.sort(:geo_near_distance.desc)
  #.geo_near([ session[:latitude].to_f,session[:longitude].to_f ]).max_distance(100).spherical   
  #.unit("km")
  #.geo_near([ session[:latitude].to_f,session[:longitude].to_f ], max_distance: radius, unit: "km".to_sym, spherical: true).sort_by!{|r| r.geo[:distance] }
  #.geo_near([ session[:latitude].to_f,session[:longitude].to_f ]).max_distance(radius)   
  #.sort(:geo_near_distance)

JQuery for the green part

 var p1 = new LatLon(Geo.parseDMS($('#lat1_{{id}}').val()), Geo.parseDMS($('#lon1_{{id}}').val()));
    var p2 = new LatLon(Geo.parseDMS($('#lat2_{{id}}').val()), Geo.parseDMS($('#lon2_{{id}}').val()));
    var new_number = parseFloat(p1.distanceTo(p2)).toFixed(2);
    $('#result-distance_{{id}}').html(new_number+' km');

Data for Provider

{ "_id" : ObjectId("5295ef0fdd5063ce1600002a"), "workdonecount" : 0, "pricescore" : 0, "servicescore" : 0, "_slugs" : [  "5295ef0fdd5063ce1600002a-1" ], "officialname" : "çeşme", "business_description" : "dsadsa", "category" : "5280ad334b315241af406c79", "business_type" : "Ticari", "tax_office" : "dads", "tax_number" : "dss", "pin" : "", "business_address" : "Balçova/İzmir, Türkiye", "latitude" : 38.3692939, "longitude" : 27.093442, "pink" : false, "hizmetkutusu_verified" : false, "user_id" : ObjectId("52946f54dd50636df6000002"), "location" : [  27.093441999999982,  38.3692939 ], "gmaps" : true, "updated_at" : ISODate("2013-11-27T13:09:36.214Z"), "created_at" : ISODate("2013-11-27T13:09:36.214Z") }
{ "_id" : ObjectId("5295f248dd5063ce16000030"), "workdonecount" : 0, "pricescore" : 0, "servicescore" : 0, "_slugs" : [  "5295f248dd5063ce16000030-1" ], "officialname" : "izmirdsads", "business_description" : "dsdsadsdsa", "category" : "5280ad334b315241af406c79", "business_type" : "Ticari", "tax_office" : "dasds", "tax_number" : "dadsa", "pin" : "", "business_address" : "Çeşme, Türkiye", "latitude" : 38.32980999999999, "longitude" : 26.3149209, "pink" : false, "hizmetkutusu_verified" : false, "user_id" : ObjectId("52946f54dd50636df6000002"), "location" : [  26.31492090000006,  38.32980999999999 ], "gmaps" : true, "updated_at" : ISODate("2013-11-27T13:23:20.423Z"), "created_at" : ISODate("2013-11-27T13:23:20.423Z") }
{ "_id" : ObjectId("5295f260dd5063ce16000032"), "workdonecount" : 0, "pricescore" : 0, "servicescore" : 0, "_slugs" : [  "5295f260dd5063ce16000032-1" ], "officialname" : "dsadsa", "business_description" : "dsadsa", "category" : "5280ad334b315241af406c79", "business_type" : "Ticari", "tax_office" : "dsadsa", "tax_number" : "dsads", "pin" : "", "business_address" : "Çiğli, 35580 İzmir, Türkiye", "latitude" : 38.496303, "longitude" : 27.0603911, "pink" : false, "hizmetkutusu_verified" : false, "user_id" : ObjectId("52946f54dd50636df6000002"), "location" : [  27.06039110000006,  38.496303 ], "gmaps" : true, "provider_image" : "gmaps1.jpg", "updated_at" : ISODate("2013-11-27T13:23:44.686Z"), "created_at" : ISODate("2013-11-27T13:23:44.686Z") }
{ "_id" : ObjectId("5295eee3dd5063ce16000026"), "workdonecount" : 0, "pricescore" : 0, "servicescore" : 0, "_slugs" : [  "5295eee3dd5063ce16000026-1" ], "officialname" : "dsdsa", "business_description" : "dadsa", "category" : "5280ad334b315241af406c79", "business_type" : "Ticari", "tax_office" : "dsa", "tax_number" : "dads", "pin" : "", "business_address" : "Buca, İzmir, Türkiye", "latitude" : 38.38813400000001, "longitude" : 27.1753358, "pink" : false, "hizmetkutusu_verified" : false, "user_id" : ObjectId("52946f54dd50636df6000002"), "location" : [  27.291124800000034,  38.3337361 ], "gmaps" : true, "updated_at" : ISODate("2013-11-27T13:08:51.544Z"), "created_at" : ISODate("2013-11-27T13:08:51.544Z") }
{ "_id" : ObjectId("5295eef5dd5063ce16000028"), "workdonecount" : 0, "pricescore" : 0, "servicescore" : 0, "_slugs" : [  "5295eef5dd5063ce16000028-1" ], "officialname" : "dsdsdsa", "business_description" : "dadsds", "category" : "5280ad334b315241af406c79", "business_type" : "Ticari", "tax_office" : "dasds", "tax_number" : "dadsa", "pin" : "", "business_address" : "Bornova, 35100 İzmir, Türkiye", "latitude" : 38.466414, "longitude" : 27.2192191, "pink" : false, "hizmetkutusu_verified" : false, "user_id" : ObjectId("52946f54dd50636df6000002"), "location" : [  27.219219100000032,  38.466414 ], "gmaps" : true, "updated_at" : ISODate("2013-11-27T13:09:10.122Z"), "created_at" : ISODate("2013-11-27T13:09:10.122Z") }
Community
  • 1
  • 1
Caner
  • 1,448
  • 23
  • 38

1 Answers1

3

I used it few months ago. This is how I used it:

class Person
  include Mongoid::Document
  field :location, :type => Array  # [lat,lng]
  index( { location: Mongo::GEO2D }, { min: -180, max: 180 })
end

Then you need to generate indexes:

rake db:mongoid:create_indexes

Then you can make the query:

center = [ 1, 10 ]
radious = 100
Person.within_circle( location: [ center, radious ] )

Or use $near query:

Person.geo_near(center).max_distance(radious)  # sorted by distance

All information is specified here:

Good luck!

rjurado01
  • 5,337
  • 3
  • 36
  • 45
  • Thank you for your answer but my question is about sorting the results. I've tried within_circle before and now I tried the way you said but the results are still not ordered by distance. Did you order your results by distance in your project? – Caner Nov 26 '13 at 11:23
  • Results of a $near query are sorted by distance (answer edited). – rjurado01 Nov 26 '13 at 13:05
  • Thank you for your help Drinor. I've tried it as before, still cannot get results. Expanded the question as seen on top. If you have an idea I would be glad to hear that. – Caner Nov 27 '13 at 14:00
  • I've done some tests and it works fine for me. Check the center and the location of persons. – rjurado01 Nov 29 '13 at 12:16
  • 1
    How do you find out `geo_near_distance` attribute from each document in-case you need to display the distance 'from' the search location? According to Mongoid V3 Doc [Link][1], each document should have a property `geo_near_distance`. [1]: http://mongoid.org/en/mongoid/v3/querying.html#geo_near – Som Poddar Jul 17 '14 at 20:52