mongoid_geospatial 2.3.0 → 2.5.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 +155 -90
- data/lib/mongoid_geospatial/fields/geometry_field.rb +2 -2
- data/lib/mongoid_geospatial/fields/point.rb +7 -1
- data/lib/mongoid_geospatial/geospatial.rb +10 -1
- data/lib/mongoid_geospatial/version.rb +1 -1
- data/spec/models/bar.rb +2 -0
- data/spec/mongoid_geospatial/field_option_spec.rb +6 -1
- data/spec/mongoid_geospatial/fields/box_spec.rb +11 -0
- data/spec/mongoid_geospatial/fields/point_spec.rb +30 -1
- metadata +4 -2
data/README.md
CHANGED
@@ -3,7 +3,6 @@ Mongoid Geospatial
|
|
3
3
|
|
4
4
|
A Mongoid Extension that simplifies the use of MongoDB spatial features.
|
5
5
|
|
6
|
-
|
7
6
|
** On beta again **
|
8
7
|
|
9
8
|
Removing some trash, improving and adding support for RGeo and GeoRuby.
|
@@ -25,98 +24,26 @@ You can also use an external Geometric/Spatial alongside.
|
|
25
24
|
# Gemfile
|
26
25
|
gem 'mongoid_geospatial'
|
27
26
|
|
28
|
-
|
29
27
|
# A place to illustrate Point, Line and Polygon
|
30
28
|
class Place
|
31
29
|
include Mongoid::Document
|
30
|
+
|
31
|
+
# Include the module
|
32
32
|
include Mongoid::Geospatial
|
33
33
|
|
34
|
+
# Just like mongoid,
|
34
35
|
field :name, type: String
|
36
|
+
# define your field, but choose a geometry type:
|
35
37
|
field :location, type: Point, :spatial => true
|
36
38
|
field :route, type: Linestring
|
37
39
|
field :area, type: Polygon
|
40
|
+
|
41
|
+
# If your are going to query on your points, don't forget to index:
|
42
|
+
spatial_index :location
|
43
|
+
|
38
44
|
end
|
39
45
|
|
40
46
|
|
41
|
-
Geometry Helpers
|
42
|
-
----------------
|
43
|
-
|
44
|
-
We currently support GeoRuby and RGeo.
|
45
|
-
If you require one of those, a #to_geo method will be available to all
|
46
|
-
spatial fields, returning the external library corresponding object.
|
47
|
-
To illustrate:
|
48
|
-
|
49
|
-
class Person
|
50
|
-
include Mongoid::Document
|
51
|
-
include Mongoid::Geospatial
|
52
|
-
|
53
|
-
field :location, type: Point
|
54
|
-
end
|
55
|
-
|
56
|
-
me = Person.new(location: [8, 8])
|
57
|
-
|
58
|
-
# Example with GeoRuby
|
59
|
-
point.class # Mongoid::Geospatial::Point
|
60
|
-
point.to_geo.class # GeoRuby::SimpleFeatures::Point
|
61
|
-
|
62
|
-
# Example with RGeo
|
63
|
-
point.class # Mongoid::Geospatial::Point
|
64
|
-
point.to_geo.class # RGeo::Geographic::SphericalPointImpl
|
65
|
-
|
66
|
-
|
67
|
-
Configure
|
68
|
-
----------------
|
69
|
-
|
70
|
-
Assemble it as you need (use a initializer file):
|
71
|
-
|
72
|
-
With RGeo
|
73
|
-
|
74
|
-
Mongoid::Geospatial.use_rgeo
|
75
|
-
# Optional
|
76
|
-
# Mongoid::Geospatial.factory = RGeo::Geographic.spherical_factory
|
77
|
-
|
78
|
-
With GeoRuby
|
79
|
-
|
80
|
-
Mongoid::Geospatial.use_georuby
|
81
|
-
|
82
|
-
Defaults (change if you know what you're doing)
|
83
|
-
|
84
|
-
Mongoid::Geospatial.lng_symbol = :x
|
85
|
-
Mongoid::Geospatial.lat_symbol = :y
|
86
|
-
Mongoid::Geospatial.earth_radius = EARTH_RADIUS
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
Model Setup
|
91
|
-
-----------
|
92
|
-
|
93
|
-
You can create Point, Line, Circle, Box and Polygon on your models:
|
94
|
-
|
95
|
-
|
96
|
-
class River
|
97
|
-
include Mongoid::Document
|
98
|
-
include Mongoid::Geospatial
|
99
|
-
|
100
|
-
field :name, type: String
|
101
|
-
field :length, type: Integer
|
102
|
-
field :discharge, type: Integer
|
103
|
-
|
104
|
-
field :source, type: Point, spatial: true
|
105
|
-
field :mouth, type: Point, spatial: true
|
106
|
-
field :course, type: Line
|
107
|
-
field :boundings, type: Box
|
108
|
-
|
109
|
-
# spatial indexing
|
110
|
-
spatial_index :mouth
|
111
|
-
|
112
|
-
# default mongodb options
|
113
|
-
spatial_index :mouth, {bit: 24, min: -180, max: 180}
|
114
|
-
end
|
115
|
-
|
116
|
-
|
117
|
-
Use
|
118
|
-
---
|
119
|
-
|
120
47
|
Generate indexes on MongoDB:
|
121
48
|
|
122
49
|
|
@@ -126,6 +53,10 @@ Generate indexes on MongoDB:
|
|
126
53
|
Points
|
127
54
|
------
|
128
55
|
|
56
|
+
Currently, MongoDB supports query operations on 2D points only, so that's
|
57
|
+
what this lib does. All geometries apart from points are just arrays
|
58
|
+
in the database. Here's is how you can input a point as:
|
59
|
+
|
129
60
|
* an unordered hash with the lat long string keys defined when setting the field (only applies for setting the field)
|
130
61
|
* longitude latitude array in that order - [long,lat] ([x, y])
|
131
62
|
* an unordered hash with latitude key(:lat, :latitude) and a longitude key(:lon, :long, :lng, :longitude)
|
@@ -150,10 +81,18 @@ We store data in the DB as a [lng,lat] array then reformat when it is returned t
|
|
150
81
|
Now to access this spatial information we can do this
|
151
82
|
|
152
83
|
hudson.mouth # => [-74.026667, 40.703056]
|
84
|
+
|
85
|
+
If you need a hash
|
86
|
+
|
87
|
+
hudson.mouth.to_hsh # => { x: -74.026667, y: 40.703056 }
|
88
|
+
|
89
|
+
If you are using GeoRuby or RGeo
|
90
|
+
|
91
|
+
hudson.mouth.to_geo # => NiceGeolib::Point
|
153
92
|
|
154
93
|
Distance and other geometrical calculations are delegated to the external
|
155
94
|
library you choosed. More info about using RGeo or GeoRuby below.
|
156
|
-
Some built in helpers:
|
95
|
+
Some built in helpers for mongoid queries:
|
157
96
|
|
158
97
|
# Returns middle point + radius
|
159
98
|
# Useful to search #within_circle
|
@@ -165,6 +104,12 @@ Some built in helpers:
|
|
165
104
|
hudson.mounth.to_hsh(:lon, :lat) # {:lon => -74.., :lat => 40..}
|
166
105
|
|
167
106
|
|
107
|
+
And for polygons and lines:
|
108
|
+
|
109
|
+
house.area.bbox # Returns polygon bounding_box (envelope)
|
110
|
+
house.area.center # Returns calculate middle point
|
111
|
+
|
112
|
+
|
168
113
|
Query
|
169
114
|
--------
|
170
115
|
|
@@ -178,30 +123,150 @@ All MongoDB queries are handled by Mongoid.
|
|
178
123
|
You can use Geometry instance directly on any query:
|
179
124
|
|
180
125
|
* near
|
126
|
+
* Bar.near(location: person.house)
|
181
127
|
* Bar.where(:location.near => person.house)
|
128
|
+
|
182
129
|
|
183
130
|
* near_sphere
|
131
|
+
* Bar.near_sphere(location: person.house)
|
184
132
|
* Bar.where(:location.near_sphere => person.house)
|
185
133
|
|
134
|
+
|
186
135
|
* within_box
|
187
|
-
* Bar.
|
136
|
+
* Bar.within_box(location: hood.area)
|
137
|
+
|
188
138
|
|
189
139
|
* within_circle
|
190
|
-
* Bar.
|
140
|
+
* Bar.within_circle(location: hood.area)
|
141
|
+
|
191
142
|
|
192
143
|
* within_circle_sphere
|
193
|
-
* Bar.
|
144
|
+
* Bar.within_circle_sphere(location: hood.area)
|
145
|
+
|
194
146
|
|
195
147
|
* within_polygon
|
196
|
-
* Bar.
|
148
|
+
* Bar.within_polygon(location: city.area)
|
149
|
+
|
150
|
+
|
151
|
+
External Libraries
|
152
|
+
------------------
|
153
|
+
|
154
|
+
Use RGeo?
|
155
|
+
https://github.com/dazuma/rgeo
|
156
|
+
|
157
|
+
RGeo is a Ruby wrapper for Proj/GEOS.
|
158
|
+
It's perfect when you need to work with complex calculations and projections.
|
159
|
+
It'll require more stuff installed to compile/work.
|
160
|
+
|
161
|
+
|
162
|
+
Use GeoRuby?
|
163
|
+
https://github.com/nofxx/geo_ruby
|
164
|
+
|
165
|
+
GeoRuby is a pure Ruby Geometry Library.
|
166
|
+
It's perfect if you want simple calculations and/or keep your stack in pure ruby.
|
167
|
+
Albeit not full featured in maths it has a handful of methods and good import/export helpers.
|
168
|
+
|
169
|
+
Use Nothing?
|
170
|
+
|
171
|
+
This lib won't stand in your way.
|
172
|
+
Write your own wrapper if you want.
|
173
|
+
|
174
|
+
|
175
|
+
Geometry Helpers
|
176
|
+
----------------
|
177
|
+
|
178
|
+
We currently support GeoRuby and RGeo.
|
179
|
+
If you require one of those, a #to_geo method will be available to all
|
180
|
+
spatial fields, returning the external library corresponding object.
|
181
|
+
To illustrate:
|
182
|
+
|
183
|
+
class Person
|
184
|
+
include Mongoid::Document
|
185
|
+
include Mongoid::Geospatial
|
186
|
+
|
187
|
+
field :location, type: Point
|
188
|
+
end
|
189
|
+
|
190
|
+
me = Person.new(location: [8, 8])
|
191
|
+
|
192
|
+
# Example with GeoRuby
|
193
|
+
point.class # Mongoid::Geospatial::Point
|
194
|
+
point.to_geo.class # GeoRuby::SimpleFeatures::Point
|
195
|
+
|
196
|
+
# Example with RGeo
|
197
|
+
point.class # Mongoid::Geospatial::Point
|
198
|
+
point.to_geo.class # RGeo::Geographic::SphericalPointImpl
|
199
|
+
|
200
|
+
|
201
|
+
Configure
|
202
|
+
----------------
|
203
|
+
|
204
|
+
Assemble it as you need (use a initializer file):
|
205
|
+
|
206
|
+
With RGeo
|
207
|
+
|
208
|
+
Mongoid::Geospatial.use_rgeo
|
209
|
+
# Optional
|
210
|
+
# Mongoid::Geospatial.factory = RGeo::Geographic.spherical_factory
|
211
|
+
|
212
|
+
|
213
|
+
With GeoRuby
|
214
|
+
|
215
|
+
Mongoid::Geospatial.use_georuby
|
216
|
+
|
217
|
+
|
218
|
+
Defaults (change if you know what you're doing)
|
219
|
+
|
220
|
+
Mongoid::Geospatial.lng_symbol = :x
|
221
|
+
Mongoid::Geospatial.lat_symbol = :y
|
222
|
+
Mongoid::Geospatial.earth_radius = EARTH_RADIUS
|
223
|
+
|
224
|
+
|
225
|
+
|
226
|
+
Model Setup
|
227
|
+
-----------
|
228
|
+
|
229
|
+
You can create Point, Line, Circle, Box and Polygon on your models:
|
230
|
+
|
231
|
+
|
232
|
+
class CrazyGeom
|
233
|
+
include Mongoid::Document
|
234
|
+
include Mongoid::Geospatial
|
235
|
+
|
236
|
+
field :location, type: Point
|
237
|
+
|
238
|
+
field :route, type: Line
|
239
|
+
field :area, type: Polygon
|
240
|
+
|
241
|
+
field :square, type: Box
|
242
|
+
field :around, type: Circle
|
243
|
+
|
244
|
+
# spatial indexing
|
245
|
+
spatial_index :mouth
|
246
|
+
|
247
|
+
# default mongodb options
|
248
|
+
spatial_index :mouth, {bit: 24, min: -180, max: 180}
|
249
|
+
|
250
|
+
# query by location
|
251
|
+
spatial_scope :location
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
|
256
|
+
Nearby
|
257
|
+
------
|
197
258
|
|
259
|
+
You can add a `spatial_scope` on your models. So you can query:
|
198
260
|
|
199
|
-
|
200
|
-
|
261
|
+
Bar.nearby(my.location)
|
262
|
+
|
263
|
+
instead of
|
201
264
|
|
202
|
-
|
265
|
+
Bar.near(location: my.location)
|
266
|
+
|
267
|
+
Good when you're drunk. Just add to your model:
|
203
268
|
|
204
|
-
field
|
269
|
+
spatial_scope :<field>
|
205
270
|
|
206
271
|
|
207
272
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Mongoid
|
2
2
|
module Geospatial
|
3
3
|
class Point
|
4
|
+
include Enumerable
|
4
5
|
attr_accessor :x, :y
|
5
6
|
|
6
7
|
def initialize(x=nil, y=nil)
|
@@ -18,6 +19,11 @@ module Mongoid
|
|
18
19
|
mongoize[args]
|
19
20
|
end
|
20
21
|
|
22
|
+
def each
|
23
|
+
yield x
|
24
|
+
yield y
|
25
|
+
end
|
26
|
+
|
21
27
|
def to_hsh xl = :x, yl = :y
|
22
28
|
{xl => x, yl => y}
|
23
29
|
end
|
@@ -58,7 +64,7 @@ module Mongoid
|
|
58
64
|
|
59
65
|
# Database -> Object
|
60
66
|
def demongoize(object)
|
61
|
-
|
67
|
+
return unless object
|
62
68
|
Point.new(*object)
|
63
69
|
end
|
64
70
|
|
@@ -26,7 +26,7 @@ module Mongoid
|
|
26
26
|
@@earth_radius = EARTH_RADIUS.dup
|
27
27
|
|
28
28
|
included do
|
29
|
-
attr_accessor :geo
|
29
|
+
# attr_accessor :geo
|
30
30
|
cattr_accessor :spatial_fields, :spatial_fields_indexed
|
31
31
|
@@spatial_fields = []
|
32
32
|
@@spatial_fields_indexed = []
|
@@ -51,6 +51,15 @@ module Mongoid
|
|
51
51
|
index({name => '2d'}, options)
|
52
52
|
end
|
53
53
|
|
54
|
+
def spatial_scope field, opts = {}
|
55
|
+
self.singleton_class.class_eval do
|
56
|
+
# define_method(:close) do |args|
|
57
|
+
define_method(:nearby) do |args|
|
58
|
+
queryable.where(field.near_sphere => args)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
54
63
|
end
|
55
64
|
|
56
65
|
end
|
data/spec/models/bar.rb
CHANGED
@@ -3,9 +3,14 @@ require "spec_helper"
|
|
3
3
|
describe Mongoid::Fields do
|
4
4
|
|
5
5
|
context "spatial" do
|
6
|
+
before do
|
7
|
+
Bar.create_indexes
|
8
|
+
end
|
6
9
|
|
7
10
|
it "should set some class methods" do
|
8
|
-
Bar.
|
11
|
+
far = Bar.create!(name: "Far", location: [7,7])
|
12
|
+
near = Bar.create!(name: "Near", location: [2,2])
|
13
|
+
Bar.nearby([1,1]).should eq([near, far])
|
9
14
|
end
|
10
15
|
|
11
16
|
end
|
@@ -9,7 +9,14 @@ describe Mongoid::Geospatial::Point do
|
|
9
9
|
|
10
10
|
it "should not fail if point is nil" do
|
11
11
|
bar = Bar.create!(name: "Moe's")
|
12
|
-
bar.location.
|
12
|
+
bar.location.should be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should set point to nil" do
|
16
|
+
bar = Bar.create!(name: "Moe's", location: [1, 1])
|
17
|
+
bar.location = nil
|
18
|
+
bar.location.should be_nil
|
19
|
+
bar.save.should be_true
|
13
20
|
end
|
14
21
|
|
15
22
|
describe "methods" do
|
@@ -36,6 +43,14 @@ describe Mongoid::Geospatial::Point do
|
|
36
43
|
bar.location.radius_sphere[1].should be_within(0.0001).of(0.00015)
|
37
44
|
end
|
38
45
|
|
46
|
+
it "should have a radius sphere helper in meters" do
|
47
|
+
bar.location.radius_sphere(1000, :m)[1].should be_within(0.0001).of(0.00015)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should have a radius sphere helper in miles" do
|
51
|
+
bar.location.radius_sphere(1, :mi)[1].should be_within(0.0001).of(0.00025)
|
52
|
+
end
|
53
|
+
|
39
54
|
end
|
40
55
|
|
41
56
|
describe "queryable" do
|
@@ -66,6 +81,15 @@ describe Mongoid::Geospatial::Point do
|
|
66
81
|
Bar.where(:location.near => jim.location).should == [ paris, prague, berlin ]
|
67
82
|
end
|
68
83
|
|
84
|
+
it "returns the documents sorted closest to furthest" do
|
85
|
+
Bar.near(location: jim.location).should == [ paris, prague, berlin ]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "returns the documents sorted closest to furthest sphere" do
|
89
|
+
person = Person.new(:location => [ 41.23, 2.9 ])
|
90
|
+
Bar.near_sphere(location: jim.location).should == [ paris, prague, berlin ]
|
91
|
+
end
|
92
|
+
|
69
93
|
it "returns the documents sorted closest to furthest sphere" do
|
70
94
|
person = Person.new(:location => [ 41.23, 2.9 ])
|
71
95
|
Bar.where(:location.near_sphere => jim.location).should == [ paris, prague, berlin ]
|
@@ -113,6 +137,11 @@ describe Mongoid::Geospatial::Point do
|
|
113
137
|
it "returns the documents within a center_sphere" do
|
114
138
|
Bar.where(:location.within_spherical_circle => [elvis.location, 0.5]).to_a.should include(mile9)
|
115
139
|
end
|
140
|
+
|
141
|
+
it "returns the documents within a box" do
|
142
|
+
Bar.within_box(location: [elvis.location, elvis.location.map(&:ceil)]).to_a.should == [ mile3 ]
|
143
|
+
end
|
144
|
+
|
116
145
|
end
|
117
146
|
|
118
147
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_geospatial
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-09-
|
13
|
+
date: 2012-09-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rgeo
|
@@ -181,6 +181,7 @@ files:
|
|
181
181
|
- spec/models/river.rb
|
182
182
|
- spec/mongoid_geospatial/extensions/core_ext_spec.rb
|
183
183
|
- spec/mongoid_geospatial/field_option_spec.rb
|
184
|
+
- spec/mongoid_geospatial/fields/box_spec.rb
|
184
185
|
- spec/mongoid_geospatial/fields/circle_spec.rb
|
185
186
|
- spec/mongoid_geospatial/fields/line_spec.rb
|
186
187
|
- spec/mongoid_geospatial/fields/point_spec.rb
|
@@ -227,6 +228,7 @@ test_files:
|
|
227
228
|
- spec/models/river.rb
|
228
229
|
- spec/mongoid_geospatial/extensions/core_ext_spec.rb
|
229
230
|
- spec/mongoid_geospatial/field_option_spec.rb
|
231
|
+
- spec/mongoid_geospatial/fields/box_spec.rb
|
230
232
|
- spec/mongoid_geospatial/fields/circle_spec.rb
|
231
233
|
- spec/mongoid_geospatial/fields/line_spec.rb
|
232
234
|
- spec/mongoid_geospatial/fields/point_spec.rb
|