mongoid_spacial 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +15 -12
- data/VERSION +1 -1
- data/lib/mongoid_spacial/contexts/mongo.rb +27 -53
- data/lib/mongoid_spacial/field_option.rb +2 -2
- data/lib/mongoid_spacial/spacial/core_ext.rb +2 -2
- data/lib/mongoid_spacial/spacial/formulas.rb +14 -17
- data/lib/mongoid_spacial/spacial/geo_near.rb +84 -0
- data/lib/mongoid_spacial/spacial.rb +7 -3
- data/mongoid_spacial.gemspec +8 -6
- data/spec/functional/mongoid/contexts/mongo_spec.rb +34 -53
- data/spec/unit/{mongoid_spacial → mongoid}/criterion/complex_spec.rb +0 -0
- data/spec/unit/{mongoid_spacial → mongoid}/criterion/inclusion_spec.rb +0 -0
- data/spec/unit/{mongoid_spacial → mongoid}/criterion/near_spacial_spec.rb +0 -0
- data/spec/unit/{mongoid_spacial → mongoid}/criterion/within_spacial_spec.rb +0 -0
- data/spec/unit/mongoid/spacial/formulas_spec.rb +37 -0
- metadata +9 -7
data/README.md
CHANGED
@@ -37,7 +37,9 @@ end
|
|
37
37
|
```
|
38
38
|
|
39
39
|
Before we manipulate the data mongoid_spacial handles is what we call points.
|
40
|
+
|
40
41
|
Points can be:
|
42
|
+
|
41
43
|
* an unordered hash with the lat long string keys defined when setting the field (only applies for setting the field)
|
42
44
|
* longitude latitude array in that order - [long,lat]
|
43
45
|
* an unordered hash with latitude key(:lat, :latitude) and a longitude key(:lon, :long, :lng, :longitude)
|
@@ -67,20 +69,21 @@ hudson.mouth #=> [-74.026667, 40.703056] # notice how this returned as a lng,la
|
|
67
69
|
# notice how the order of lng and lat were switched. it will always come out like this when using spacial.
|
68
70
|
```
|
69
71
|
Mongoid Geo has extended all built in spacial symbol extentions
|
72
|
+
|
70
73
|
* near
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
* River.where(:source.near => [-73.98, 40.77])
|
75
|
+
* River.where(:source.near => [[-73.98, 40.77],5]) # sets max distance of 5
|
76
|
+
* River.where(:source.near => {:point => [-73.98, 40.77], :max => 5}) # sets max distance of 5
|
77
|
+
* River.where(:source.near(:sphere) => [[-73.98, 40.77],5]) # sets max distance of 5 radians
|
78
|
+
* River.where(:source.near(:sphere) => {:point => [-73.98, 40.77], :max => 5, :unit => :km}) # sets max distance of 5 km
|
79
|
+
* River.where(:source.near(:sphere) => [-73.98, 40.77])
|
77
80
|
* within
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
* River.where(:source.within(:box) => [[-73.99756,40.73083], [-73.988135,40.741404]])
|
82
|
+
* River.where(:source.within(:box) => [ {:lat => 40.73083, :lng => -73.99756}, [-73.988135,40.741404]])
|
83
|
+
* River.where(:source.within(:polygon) => [ [ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ] ]
|
84
|
+
* River.where(:source.within(:polygon) => { a : { x : 10, y : 20 }, b : { x : 15, y : 25 }, c : { x : 20, y : 20 } })
|
85
|
+
* River.where(:source.within(:center) => [[-73.98, 40.77],5]) # same format as near
|
86
|
+
* River.where(:source.within(:center_sphere) => [[-73.98, 40.77],5]) # same format as near(:sphere)
|
84
87
|
|
85
88
|
One of the most handy features we have added is geo_near finder
|
86
89
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
@@ -2,21 +2,21 @@
|
|
2
2
|
module Mongoid #:nodoc:
|
3
3
|
module Contexts #:nodoc:
|
4
4
|
class Mongo #:nodoc:
|
5
|
-
|
5
|
+
|
6
6
|
# Fetches rows from the data base sorted by distance.
|
7
7
|
# In MongoDB versions 1.7 and above it returns a distance.
|
8
8
|
# Uses all criteria chains except without, only, asc, desc, order_by
|
9
9
|
#
|
10
10
|
# @example Minimal Query
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# Address.geo_near([70,40])
|
13
13
|
#
|
14
14
|
# @example Chained Query
|
15
|
-
#
|
15
|
+
#
|
16
16
|
# Address.where(:state => 'ny').geo_near([70,40])
|
17
17
|
#
|
18
18
|
# @example Calc Distances Query
|
19
|
-
#
|
19
|
+
#
|
20
20
|
# Address.geo_near([70,40], :max_distance => 5, :unit => 5)
|
21
21
|
#
|
22
22
|
# @param [ Array, Hash, #to_lng_lat ] center The center of where to calculate distance from
|
@@ -31,57 +31,29 @@ module Mongoid #:nodoc:
|
|
31
31
|
#
|
32
32
|
# @return [ Array ] Sorted Rows
|
33
33
|
def geo_near(center, opts = {})
|
34
|
+
opts = self.options.merge(opts)
|
35
|
+
# convert point
|
34
36
|
center = center.to_lng_lat if center.respond_to?(:to_lng_lat)
|
35
37
|
|
38
|
+
# set default opts
|
36
39
|
if distance_multiplier = Mongoid::Spacial.earth_radius[opts.delete(:unit)]
|
37
40
|
opts[:distance_multiplier] = distance_multiplier
|
38
41
|
end
|
39
42
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
result.each do |key,value|
|
51
|
-
res.geo[key.snakecase.to_sym] = value
|
43
|
+
if opts.has_key?(:page)
|
44
|
+
opts[:page] ||= 1
|
45
|
+
opts[:paginator] ||= Mongoid::Spacial.paginator
|
46
|
+
if opts[:paginator] == :will_paginate
|
47
|
+
opts[:per_page] ||= klass.per_page
|
48
|
+
elsif opts[:paginator] == :kaminari
|
49
|
+
opts[:per_page] ||= Kaminari.config.default_per_page
|
50
|
+
else
|
51
|
+
opts[:per_page] ||= 25
|
52
52
|
end
|
53
|
-
# dist_options[:formula] = opts[:formula] if opts[:formula]
|
54
|
-
opts[:calculate] = klass.spacial_fields_indexed if klass.spacial_fields_indexed.kind_of?(Array) && opts[:calculate] == true
|
55
|
-
if opts[:calculate]
|
56
|
-
opts[:calculate] = [opts[:calculate]] unless opts[:calculate].kind_of? Array
|
57
|
-
opts[:calculate] = opts[:calculate].map(&:to_sym) & geo_fields
|
58
|
-
if klass.spacial_fields_indexed.kind_of?(Array) && klass.spacial_fields_indexed.size == 1
|
59
|
-
primary = klass.spacial_fields_indexed.first
|
60
|
-
end
|
61
|
-
opts[:calculate].each do |key|
|
62
|
-
key = (key.to_s+'_distance').to_s
|
63
|
-
res.geo[key] = res.distance_from(key,center, opts[:distance_multiplier])
|
64
|
-
res.geo[:distance] = res.geo[key] if primary && key == primary
|
65
|
-
end
|
66
|
-
end
|
67
|
-
res
|
68
|
-
end
|
69
|
-
else
|
70
|
-
rows = []
|
71
|
-
end
|
72
|
-
# if opts.has_key?(:page) || opts[:paginator]
|
73
|
-
# opts[:paginator] ||= Mongoid::Spacial::Config.paginator
|
74
|
-
# if opts[:paginator] == :kaminari
|
75
|
-
|
76
|
-
# elsif opts[:paginator] == :will_paginate
|
77
|
-
# end
|
78
|
-
# end
|
79
|
-
|
80
|
-
if self.options[:skip] && rows.size > self.options[:skip]
|
81
|
-
rows[self.options[:skip]..rows.size-1]
|
82
|
-
else
|
83
|
-
rows
|
84
53
|
end
|
54
|
+
query = create_geo_near_query(center,opts)
|
55
|
+
results = klass.db.command(query)
|
56
|
+
Mongoid::Spacial::GeoNear.new(klass,results,opts)
|
85
57
|
end
|
86
58
|
|
87
59
|
private
|
@@ -90,14 +62,16 @@ module Mongoid #:nodoc:
|
|
90
62
|
# minimum query
|
91
63
|
query = {
|
92
64
|
:geoNear => klass.to_s.tableize,
|
93
|
-
:near => center,
|
65
|
+
:near => center,
|
94
66
|
}
|
95
67
|
|
96
68
|
# create limit and use skip
|
97
|
-
if opts[:num]
|
98
|
-
query['num'] = (
|
99
|
-
elsif
|
100
|
-
query['num'] = (
|
69
|
+
if opts[:num]
|
70
|
+
query['num'] = (opts[:skip] || 0) + opts[:num].to_i
|
71
|
+
elsif opts[:limit]
|
72
|
+
query['num'] = (opts[:skip] || 0) + opts[:limit]
|
73
|
+
elsif opts[:page]
|
74
|
+
query['num'] = (opts[:page] * opts[:per_page])
|
101
75
|
end
|
102
76
|
|
103
77
|
# allow the use of complex werieis
|
@@ -112,7 +86,7 @@ module Mongoid #:nodoc:
|
|
112
86
|
query['maxDistance'] = query['maxDistance']/opts[:distance_multiplier] if opts[:distance_multiplier]
|
113
87
|
end
|
114
88
|
|
115
|
-
if klass.db.connection.server_version >= '1.7'
|
89
|
+
if klass.db.connection.server_version >= '1.7'
|
116
90
|
query['spherical'] = true if opts[:spherical]
|
117
91
|
|
118
92
|
# mongodb < 1.7 returns degrees but with earth flat. in Mongodb 1.7 you can set sphere and let mongodb calculate the distance in Miles or KM
|
@@ -16,7 +16,7 @@ field.option :spacial do |model,field,options|
|
|
16
16
|
|
17
17
|
define_method field.name do
|
18
18
|
output = self[field.name] || [nil,nil]
|
19
|
-
output = (options[:return_array]) ? lng_lat_a : {lng_meth => output[0], lat_meth => output[
|
19
|
+
output = (options[:return_array]) ? lng_lat_a : {lng_meth => output[0], lat_meth => output[1]}
|
20
20
|
return options[:class].new(output) if options[:class]
|
21
21
|
output
|
22
22
|
end
|
@@ -29,7 +29,7 @@ field.option :spacial do |model,field,options|
|
|
29
29
|
end
|
30
30
|
self[field.name]=arg
|
31
31
|
return arg[0..1] if options[:return_array]
|
32
|
-
return h = {lng_meth => arg[0], lat_meth => arg[
|
32
|
+
return h = {lng_meth => arg[0], lat_meth => arg[1]} if options[:class].blank?
|
33
33
|
options[:class].new(h)
|
34
34
|
end
|
35
35
|
end
|
@@ -14,14 +14,14 @@ class Hash
|
|
14
14
|
v = (Mongoid::Spacial.lat_symbols & self.keys).first
|
15
15
|
return self[v] if !v.nil? && self[v]
|
16
16
|
raise "Hash must contain #{Mongoid::Spacial.lat_symbols.inspect} if ruby version is less than 1.9" if RUBY_VERSION.to_f < 1.9
|
17
|
-
raise "Hash cannot contain #{Mongoid::Spacial.lng_symbols.inspect} as the second item if there is no #{Mongoid::Spacial.lat_symbols.inspect}" if Mongoid::
|
17
|
+
raise "Hash cannot contain #{Mongoid::Spacial.lng_symbols.inspect} as the second item if there is no #{Mongoid::Spacial.lat_symbols.inspect}" if Mongoid::Spacial.lng_symbols.index(self.keys[1])
|
18
18
|
self.values[1]
|
19
19
|
end
|
20
20
|
|
21
21
|
def to_lng
|
22
22
|
v = (Mongoid::Spacial.lng_symbols & self.keys).first
|
23
23
|
return self[v] if !v.nil? && self[v]
|
24
|
-
raise "Hash cannot contain #{Mongoid::Spacial.lat_symbols.inspect} as the first item if there is no #{Mongoid::Spacial.lng_symbols.inspect}" if Mongoid::
|
24
|
+
raise "Hash cannot contain #{Mongoid::Spacial.lat_symbols.inspect} as the first item if there is no #{Mongoid::Spacial.lng_symbols.inspect}" if Mongoid::Spacial.lat_symbols.index(self.keys[0])
|
25
25
|
self.values[0]
|
26
26
|
end
|
27
27
|
end
|
@@ -1,9 +1,12 @@
|
|
1
1
|
module Mongoid
|
2
2
|
module Spacial
|
3
3
|
module Formulas
|
4
|
-
RAD_PER_DEG =
|
4
|
+
RAD_PER_DEG = Math::PI/180
|
5
|
+
|
6
|
+
def self.n_vector(point1,point2)
|
7
|
+
p1 = point1.map{|deg| deg * RAD_PER_DEG}
|
8
|
+
p2 = point2.map{|deg| deg * RAD_PER_DEG}
|
5
9
|
|
6
|
-
def n_vector(p1,p2)
|
7
10
|
sin_x1 = Math.sin(p1[0])
|
8
11
|
cos_x1 = Math.cos(p1[0])
|
9
12
|
|
@@ -19,26 +22,20 @@ module Mongoid
|
|
19
22
|
cross_prod = (cos_y1*cos_x1 * cos_y2*cos_x2) +
|
20
23
|
(cos_y1*sin_x1 * cos_y2*sin_x2) +
|
21
24
|
(sin_y1 * sin_y2)
|
22
|
-
Math.acos(cross_prod)
|
23
|
-
end
|
24
25
|
|
25
|
-
|
26
|
-
lon1,lat1=p1
|
27
|
-
lon2,lat2=p2
|
26
|
+
return cross_prod > 0 ? 0 : Math::PI if (cross_prod >= 1 || cross_prod <= -1)
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
dlon_rad = dlon * RAD_PER_DEG
|
33
|
-
dlat_rad = dlat * RAD_PER_DEG
|
28
|
+
Math.acos(cross_prod)
|
29
|
+
end
|
34
30
|
|
35
|
-
|
36
|
-
|
31
|
+
def self.haversine(point1,point2)
|
32
|
+
p1 = point1.map{|deg| deg * RAD_PER_DEG}
|
33
|
+
p2 = point2.map{|deg| deg * RAD_PER_DEG}
|
37
34
|
|
38
|
-
|
39
|
-
|
35
|
+
dlon = p2[0] - p1[0]
|
36
|
+
dlat = p2[1] - p1[1]
|
40
37
|
|
41
|
-
a = (Math.sin(
|
38
|
+
a = (Math.sin(dlat/2))**2 + Math.cos(p1[1]) * Math.cos(p2[1]) * (Math.sin(dlon/2))**2
|
42
39
|
|
43
40
|
2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a))
|
44
41
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Spacial
|
3
|
+
class GeoNear < Array
|
4
|
+
attr_reader :stats
|
5
|
+
|
6
|
+
def initialize(klass,results,opts = {})
|
7
|
+
raise "class must include Mongoid::Spacial::Document" unless klass.respond_to?(:spacial_fields_indexed)
|
8
|
+
@klass, @stats,@opts = klass,results['stats'],opts
|
9
|
+
|
10
|
+
@_original_array = results['results'].collect do |result|
|
11
|
+
res = Mongoid::Factory.from_db(klass, result.delete('obj'))
|
12
|
+
res.geo = {}
|
13
|
+
# camel case is awkward in ruby when using variables...
|
14
|
+
if result['dis']
|
15
|
+
res.geo[:distance] = result.delete('dis').to_f
|
16
|
+
end
|
17
|
+
result.each do |key,value|
|
18
|
+
res.geo[key.snakecase.to_sym] = value
|
19
|
+
end
|
20
|
+
# dist_options[:formula] = opts[:formula] if opts[:formula]
|
21
|
+
opts[:calculate] = klass.spacial_fields_indexed if klass.spacial_fields_indexed.kind_of?(Array) && opts[:calculate] == true
|
22
|
+
if opts[:calculate]
|
23
|
+
opts[:calculate] = [opts[:calculate]] unless opts[:calculate].kind_of? Array
|
24
|
+
opts[:calculate] = opts[:calculate].map(&:to_sym) & geo_fields
|
25
|
+
if klass.spacial_fields_indexed.kind_of?(Array) && klass.spacial_fields_indexed.size == 1
|
26
|
+
primary = klass.spacial_fields_indexed.first
|
27
|
+
end
|
28
|
+
opts[:calculate].each do |key|
|
29
|
+
key = (key.to_s+'_distance').to_sym
|
30
|
+
res.geo[key] = res.distance_from(key,center, opts[:distance_multiplier])
|
31
|
+
res.geo[:distance] = res.geo[key] if primary && key == primary
|
32
|
+
end
|
33
|
+
end
|
34
|
+
res
|
35
|
+
end
|
36
|
+
|
37
|
+
if opts[:page]
|
38
|
+
start = (opts[:page]-1)*opts[:per_page] # assuming current_page is 1 based.
|
39
|
+
super(@_original_array[start, opts[:per_page]])
|
40
|
+
elsif opts[:skip] && @_original_array.size > opts[:skip]
|
41
|
+
super(@_original_array[opts[:skip]..-1])
|
42
|
+
else
|
43
|
+
super(@_original_array)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def current_page
|
48
|
+
@opts[:page]
|
49
|
+
end
|
50
|
+
|
51
|
+
def num_pages
|
52
|
+
@stats['nscanned']/@opts[:per_page]
|
53
|
+
end
|
54
|
+
alias_method :total_pages, :num_pages
|
55
|
+
|
56
|
+
def out_of_bounds?
|
57
|
+
current_page > total_pages
|
58
|
+
end
|
59
|
+
|
60
|
+
def limit_value
|
61
|
+
@opts[:per_page]
|
62
|
+
end
|
63
|
+
alias_method :per_page, :limit_value
|
64
|
+
|
65
|
+
def offset
|
66
|
+
(current_page - 1) * per_page
|
67
|
+
end
|
68
|
+
|
69
|
+
# current_page - 1 or nil if there is no previous page
|
70
|
+
def previous_page
|
71
|
+
current_page > 1 ? (current_page - 1) : nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# current_page + 1 or nil if there is no next page
|
75
|
+
def next_page
|
76
|
+
current_page < total_pages ? (current_page + 1) : nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def total_entries
|
80
|
+
@stats['nscanned']
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'mongoid_spacial/spacial/core_ext'
|
2
|
+
require 'mongoid_spacial/spacial/formulas'
|
2
3
|
module Mongoid
|
3
4
|
module Spacial
|
4
|
-
autoload :Formulas, 'mongoid_spacial/spacial/formulas'
|
5
5
|
autoload :Document, 'mongoid_spacial/spacial/document'
|
6
|
-
|
6
|
+
autoload :GeoNear, 'mongoid_spacial/spacial/geo_near'
|
7
|
+
|
7
8
|
EARTH_RADIUS_KM = 6371 # taken directly from mongodb
|
8
9
|
|
9
10
|
EARTH_RADIUS = {
|
@@ -12,7 +13,7 @@ module Mongoid
|
|
12
13
|
:mi => EARTH_RADIUS_KM*0.621371192, # taken directly from mongodb
|
13
14
|
:ft => EARTH_RADIUS_KM*5280*0.621371192,
|
14
15
|
}
|
15
|
-
|
16
|
+
|
16
17
|
LNG_SYMBOLS = [:x, :lon, :long, :lng, :longitude]
|
17
18
|
LAT_SYMBOLS = [:y, :lat, :latitude]
|
18
19
|
|
@@ -33,5 +34,8 @@ module Mongoid
|
|
33
34
|
|
34
35
|
mattr_accessor :distance_formula
|
35
36
|
@@distance_formula = :n_vector
|
37
|
+
|
38
|
+
mattr_accessor :paginator
|
39
|
+
@@paginator = :kaminari
|
36
40
|
end
|
37
41
|
end
|
data/mongoid_spacial.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mongoid_spacial}
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{Ryan Ong}]
|
12
|
-
s.date = %q{2011-06-
|
12
|
+
s.date = %q{2011-06-23}
|
13
13
|
s.description = %q{A Mongoid Extention that simplifies and adds support for MongoDB Geo Spacial Calculations.}
|
14
14
|
s.email = %q{ryanong@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -40,6 +40,7 @@ Gem::Specification.new do |s|
|
|
40
40
|
"lib/mongoid_spacial/spacial/core_ext.rb",
|
41
41
|
"lib/mongoid_spacial/spacial/document.rb",
|
42
42
|
"lib/mongoid_spacial/spacial/formulas.rb",
|
43
|
+
"lib/mongoid_spacial/spacial/geo_near.rb",
|
43
44
|
"mongoid_spacial.gemspec",
|
44
45
|
"spec/config/mongod.conf",
|
45
46
|
"spec/config/mongoid.yml",
|
@@ -116,10 +117,11 @@ Gem::Specification.new do |s|
|
|
116
117
|
"spec/models/wiki_page.rb",
|
117
118
|
"spec/spec_helper.rb",
|
118
119
|
"spec/support/authentication.rb",
|
119
|
-
"spec/unit/
|
120
|
-
"spec/unit/
|
121
|
-
"spec/unit/
|
122
|
-
"spec/unit/
|
120
|
+
"spec/unit/mongoid/criterion/complex_spec.rb",
|
121
|
+
"spec/unit/mongoid/criterion/inclusion_spec.rb",
|
122
|
+
"spec/unit/mongoid/criterion/near_spacial_spec.rb",
|
123
|
+
"spec/unit/mongoid/criterion/within_spacial_spec.rb",
|
124
|
+
"spec/unit/mongoid/spacial/formulas_spec.rb"
|
123
125
|
]
|
124
126
|
s.homepage = %q{http://github.com/ryanong/mongoid_spacial}
|
125
127
|
s.licenses = [%q{MIT}]
|
@@ -1,97 +1,78 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Mongoid::Contexts::Mongo do
|
4
|
+
describe "#geo_near" do
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
before do
|
7
|
+
Bar.delete_all
|
8
|
+
Bar.create_indexes
|
9
|
+
end
|
10
|
+
|
11
|
+
let!(:jfk) do
|
12
|
+
Bar.create(:name => 'jfk', :location => [-73.77694444, 40.63861111 ])
|
13
|
+
end
|
14
|
+
|
15
|
+
let!(:lax) do
|
16
|
+
Bar.create(:name => 'lax', :location => [-118.40, 33.94])
|
17
|
+
end
|
13
18
|
|
14
|
-
let!(:berlin) do
|
15
|
-
Bar.create(:location => [46, 12], :name => 'Berlin')
|
16
|
-
end
|
17
|
-
describe "geo_near" do
|
18
19
|
it "should work with specifying specific center and different location attribute on collction" do
|
19
|
-
location
|
20
|
-
|
21
|
-
near.should == [munich,berlin]
|
22
|
-
near.first.geo[:distance].should > 0
|
20
|
+
Bar.geo_near(lax.location, :spherical => true).should == [lax, jfk]
|
21
|
+
Bar.geo_near(jfk.location, :spherical => true).should == [jfk, lax]
|
23
22
|
end
|
24
23
|
|
25
24
|
describe 'option :num' do
|
26
25
|
it "should limit number of results to 1" do
|
27
|
-
location
|
28
|
-
Bar.geo_near(location, :num => 1).size.should == 1
|
26
|
+
Bar.geo_near(jfk.location, :num => 1).size.should == 1
|
29
27
|
end
|
30
28
|
end
|
31
|
-
|
29
|
+
|
32
30
|
describe 'option :maxDistance' do
|
33
|
-
it "should
|
34
|
-
location
|
35
|
-
# db.runCommand({ geo_near : "points", near :[45.1, 11.1]}).results;
|
36
|
-
# dis: is 0.14141869255648362 and 1.2727947855285668
|
37
|
-
Bar.geo_near(location, :max_distance => 0.2).should == [munich]
|
31
|
+
it "should get 1 item" do
|
32
|
+
Bar.geo_near(lax.location, :spherical => true, :max_distance => 2465/Mongoid::Spacial.earth_radius[:mi]).size.should == 1
|
38
33
|
end
|
34
|
+
it "should get 2 items" do
|
35
|
+
Bar.geo_near(lax.location, :spherical => true, :max_distance => 2480/Mongoid::Spacial.earth_radius[:mi]).size.should == 2
|
36
|
+
end
|
37
|
+
|
39
38
|
end
|
40
|
-
|
41
|
-
describe 'option :
|
39
|
+
|
40
|
+
describe 'option :distance_multiplier' do
|
42
41
|
it "should multiply returned distance with multiplier" do
|
43
|
-
|
44
|
-
Bar.geo_near(location, :distance_multiplier => 4).first.geo[:distance].should > 0
|
42
|
+
Bar.geo_near(lax.location, :spherical => true, :distance_multiplier=> Mongoid::Spacial.earth_radius[:mi]).second.geo[:distance].to_i.should be_within(1).of(2469)
|
45
43
|
end
|
46
44
|
end
|
47
|
-
|
45
|
+
|
48
46
|
describe 'option :unit' do
|
49
47
|
it "should multiply returned distance with multiplier" do
|
50
|
-
|
51
|
-
distance = Bar.geo_near(location, :unit => :mi).first.geo[:distance]
|
52
|
-
distance.should > 559
|
53
|
-
distance.should < 560
|
48
|
+
Bar.geo_near(lax.location, :spherical => true, :unit => :mi).second.geo[:distance].to_i.should be_within(1).of(2469)
|
54
49
|
end
|
55
50
|
|
56
51
|
it "should convert max_distance to radians with unit" do
|
57
|
-
|
58
|
-
near = Bar.geo_near(location, :max_distance => 570, :unit => :mi)
|
59
|
-
near.size.should == 1
|
60
|
-
near.first.should == munich
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should convert max_distance to radians with unit" do
|
64
|
-
location = [45.1, 11.1]
|
65
|
-
Bar.geo_near(location, :max_distance => 570, :distance_multiplier => 4, :unit => :mi).first.should == munich
|
52
|
+
Bar.geo_near(lax.location, :spherical => true, :max_distance => 2465, :unit => :mi).size.should == 1
|
66
53
|
end
|
67
54
|
|
68
55
|
end
|
69
56
|
|
70
57
|
describe 'option :query' do
|
71
58
|
it "should filter using extra query option" do
|
72
|
-
location = [45.1, 11.1]
|
73
59
|
# two record in the collection, only one's name is Munich
|
74
|
-
Bar.geo_near(location, :query => {:name =>
|
60
|
+
Bar.geo_near(jfk.location, :query => {:name => jfk.name}).should == [jfk]
|
75
61
|
end
|
76
62
|
end
|
77
63
|
|
78
64
|
describe 'criteria chaining' do
|
79
65
|
it "should filter by where" do
|
80
|
-
location
|
81
|
-
|
82
|
-
a = Bar.where(:name => 'Munich')
|
83
|
-
# p a.selector
|
84
|
-
# a.geo_near(location).size.should == 1
|
66
|
+
Bar.where(:name => jfk.name).geo_near(jfk.location).should == [jfk]
|
67
|
+
Bar.any_of({:name => jfk.name},{:name => lax.name}).geo_near(jfk.location).should == [jfk,lax]
|
85
68
|
end
|
86
69
|
|
87
70
|
it 'should skip 1' do
|
88
|
-
location
|
89
|
-
Bar.skip(1).geo_near(location).size.should == 1
|
71
|
+
Bar.skip(1).geo_near(jfk.location).size.should == 1
|
90
72
|
end
|
91
73
|
|
92
74
|
it 'should limit 1' do
|
93
|
-
location
|
94
|
-
Bar.limit(1).geo_near(location).size.should == 1
|
75
|
+
Bar.limit(1).geo_near(jfk.location).size.should == 1
|
95
76
|
end
|
96
77
|
|
97
78
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Spacial::Formulas do
|
4
|
+
context "#n_vector" do
|
5
|
+
it {
|
6
|
+
bna = [-86.67, 36.12]
|
7
|
+
lax = [-118.40, 33.94]
|
8
|
+
dist1 = Mongoid::Spacial::Formulas.n_vector(bna, lax)
|
9
|
+
dist2 = Mongoid::Spacial::Formulas.n_vector(lax, bna)
|
10
|
+
|
11
|
+
# target is 0.45306
|
12
|
+
dist1.should be_within(0.00001).of(0.45306)
|
13
|
+
dist2.should be_within(0.00001).of(0.45306)
|
14
|
+
}
|
15
|
+
it {
|
16
|
+
# actual distance 2471.788
|
17
|
+
jfk = [-73.77694444, 40.63861111 ]
|
18
|
+
lax = [-118.40, 33.94]
|
19
|
+
|
20
|
+
dist = Mongoid::Spacial::Formulas.n_vector(jfk, lax) * Mongoid::Spacial.earth_radius[:mi]
|
21
|
+
dist.should be_within(1).of(2469)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
context "#haversine" do
|
26
|
+
it {
|
27
|
+
# actual distance 2471.788
|
28
|
+
jfk = [-73.77694444, 40.63861111 ]
|
29
|
+
lax = [-118.40, 33.94]
|
30
|
+
|
31
|
+
dist = Mongoid::Spacial::Formulas.haversine(jfk, lax) * Mongoid::Spacial.earth_radius[:mi]
|
32
|
+
dist.should be_within(1).of(2469)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: mongoid_spacial
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0
|
5
|
+
version: 0.1.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ryan Ong
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-06-
|
13
|
+
date: 2011-06-23 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: mongoid
|
@@ -166,6 +166,7 @@ files:
|
|
166
166
|
- lib/mongoid_spacial/spacial/core_ext.rb
|
167
167
|
- lib/mongoid_spacial/spacial/document.rb
|
168
168
|
- lib/mongoid_spacial/spacial/formulas.rb
|
169
|
+
- lib/mongoid_spacial/spacial/geo_near.rb
|
169
170
|
- mongoid_spacial.gemspec
|
170
171
|
- spec/config/mongod.conf
|
171
172
|
- spec/config/mongoid.yml
|
@@ -242,10 +243,11 @@ files:
|
|
242
243
|
- spec/models/wiki_page.rb
|
243
244
|
- spec/spec_helper.rb
|
244
245
|
- spec/support/authentication.rb
|
245
|
-
- spec/unit/
|
246
|
-
- spec/unit/
|
247
|
-
- spec/unit/
|
248
|
-
- spec/unit/
|
246
|
+
- spec/unit/mongoid/criterion/complex_spec.rb
|
247
|
+
- spec/unit/mongoid/criterion/inclusion_spec.rb
|
248
|
+
- spec/unit/mongoid/criterion/near_spacial_spec.rb
|
249
|
+
- spec/unit/mongoid/criterion/within_spacial_spec.rb
|
250
|
+
- spec/unit/mongoid/spacial/formulas_spec.rb
|
249
251
|
homepage: http://github.com/ryanong/mongoid_spacial
|
250
252
|
licenses:
|
251
253
|
- MIT
|
@@ -259,7 +261,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
259
261
|
requirements:
|
260
262
|
- - ">="
|
261
263
|
- !ruby/object:Gem::Version
|
262
|
-
hash: -
|
264
|
+
hash: -2362332534301507743
|
263
265
|
segments:
|
264
266
|
- 0
|
265
267
|
version: "0"
|