Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of git://github.com/kristianmandrup/mongoid_geo…

…spatial into geospatial

Conflicts:
	lib/mongoid_geospatial/geospatial/geo_near_results.rb
	spec/functional/geospatial/geo_near_results_spec.rb
  • Loading branch information...
commit 7c45933f0333c5196298499daa01ddc09bc8e4a3 2 parents 972e90b + ed72cf0
@niedhui authored
Showing with 1,108 additions and 618 deletions.
  1. +12 −1 Gemfile
  2. +0 −20 LICENSE.txt
  3. +175 −17 README.md
  4. +24 −0 lib/mongoid_geospatial.rb
  5. +22 −20 lib/{mongoid_spacial → mongoid_geospatial}/contexts/mongo.rb
  6. +117 −0 lib/mongoid_geospatial/contextual/mongo.rb
  7. +10 −0 lib/mongoid_geospatial/criteria.rb
  8. +1 −1  lib/{mongoid_spacial → mongoid_geospatial}/criterion/complex.rb
  9. +14 −0 lib/mongoid_geospatial/criterion/inclusion.rb
  10. +11 −9 lib/{mongoid_spacial/criterion/near_spacial.rb → mongoid_geospatial/criterion/near_spatial.rb}
  11. +11 −9 lib/{mongoid_spacial/criterion/within_spacial.rb → mongoid_geospatial/criterion/within_spatial.rb}
  12. +13 −0 lib/mongoid_geospatial/extensions/rgeo_spherical_point_impl.rb
  13. +46 −0 lib/mongoid_geospatial/extensions/symbol.rb
  14. +16 −0 lib/mongoid_geospatial/field_option.rb
  15. +21 −0 lib/mongoid_geospatial/fields/line_string.rb
  16. +20 −0 lib/mongoid_geospatial/fields/mongoid2/line_string.rb
  17. +20 −0 lib/mongoid_geospatial/fields/mongoid2/point.rb
  18. +23 −0 lib/mongoid_geospatial/fields/mongoid2/polygon.rb
  19. +57 −0 lib/mongoid_geospatial/fields/point.rb
  20. +25 −0 lib/mongoid_geospatial/fields/polygon.rb
  21. 0  lib/{mongoid_spacial → mongoid_geospatial}/finders.rb
  22. +90 −0 lib/mongoid_geospatial/geospatial.rb
  23. +29 −0 lib/mongoid_geospatial/geospatial/core_ext.rb
  24. +8 −8 lib/{mongoid_spacial/spacial → mongoid_geospatial/geospatial}/geo_near_results.rb
  25. +5 −0 lib/mongoid_geospatial/version.rb
  26. +0 −11 lib/mongoid_spacial.rb
  27. +0 −5 lib/mongoid_spacial/criteria.rb
  28. +0 −3  lib/mongoid_spacial/criterion.rb
  29. +0 −14 lib/mongoid_spacial/criterion/inclusion.rb
  30. +0 −22 lib/mongoid_spacial/extentions/hash/criteria_helpers.rb
  31. +0 −46 lib/mongoid_spacial/extentions/symbol/inflections.rb
  32. +0 −38 lib/mongoid_spacial/field_option.rb
  33. +0 −56 lib/mongoid_spacial/spacial.rb
  34. +0 −27 lib/mongoid_spacial/spacial/core_ext.rb
  35. +0 −29 lib/mongoid_spacial/spacial/document.rb
  36. +0 −52 lib/mongoid_spacial/spacial/formulas.rb
  37. +0 −5 lib/mongoid_spacial/spacial/version.rb
  38. +27 −0 mongoid_geospatial.gemspec
  39. +0 −27 mongoid_spacial.gemspec
  40. +0 −18 spec/config/mongoid.yml
  41. +25 −15 spec/functional/{mongoid → }/contexts/mongo_spec.rb
  42. +17 −13 spec/functional/{mongoid → }/criterion/inclusion_spec.rb
  43. +6 −8 spec/functional/{mongoid/spacial → geospatial}/geo_near_results_spec.rb
  44. +0 −18 spec/functional/mongoid/spacial_spec.rb
  45. +65 −0 spec/functional/mongoid_geospatial_spec.rb
  46. +7 −5 spec/models/bar.rb
  47. +10 −0 spec/models/farm.rb
  48. +9 −9 spec/models/river.rb
  49. 0  spec/{unit/mongoid → mongoid_geospatial}/criterion/complex_spec.rb
  50. 0  spec/{unit/mongoid → mongoid_geospatial}/criterion/inclusion_spec.rb
  51. +3 −3 spec/{unit/mongoid/criterion/near_spacial_spec.rb → mongoid_geospatial/criterion/near_spatial_spec.rb}
  52. +54 −0 spec/mongoid_geospatial/criterion/within_spatial_spec.rb
  53. +25 −0 spec/mongoid_geospatial/geospatial_spec.rb
  54. +34 −0 spec/mongoid_setup.rb
  55. +35 −12 spec/spec_helper.rb
  56. +2 −2 spec/support/authentication.rb
  57. 0  spec/{config → support}/mongod.conf
  58. +19 −0 spec/support/mongoid.yml
  59. +0 −52 spec/unit/mongoid/criterion/within_spacial_spec.rb
  60. +0 −37 spec/unit/mongoid/spacial/formulas_spec.rb
  61. +0 −6 spec/unit/mongoid/spacial_spec.rb
View
13 Gemfile
@@ -1,4 +1,15 @@
source 'http://rubygems.org'
-# Specify your gem's dependencies in mongoid_spacial.gemspec
+# Specify gem's dependencies in mongoid_geospatial.gemspec
gemspec
+
+gem 'rgeo'
+
+gem 'mongoid', '~> 2.4' # all specs pass on 2.4.10 :)
+# gem 'mongoid', :git => 'git://github.com/mongoid/mongoid'
+
+group :development do
+ gem 'rspec'
+ gem 'pry'
+# gem 'fuubar'
+end
View
20 LICENSE.txt
@@ -1,20 +0,0 @@
-Copyright (c) 2011 Ryan Ong
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
192 README.md
@@ -1,14 +1,20 @@
-Mongoid Spacial
-============
+Mongoid Geospatial
+==================
+
+A Mongoid Extension that simplifies and adds support for MongoDB and
+RGeo Spatial Calculations.
+
+*WARNING* There are no plans to support MongoDB < 2.0.
+
+*WARNING* Experimental Mongoid 3.0 support.
-A Mongoid Extention that simplifies and adds support for MongoDB Geo Spacial Calculations.
Quick Start
-----------
-Add mongoid_spacial to your Gemfile:
+Add mongoid_geospatial to your Gemfile:
```ruby
-gem 'mongoid_spacial'
+gem 'mongoid_geospatial'
```
Set up some slugs:
@@ -16,24 +22,32 @@ Set up some slugs:
```ruby
class River
include Mongoid::Document
- include Mongoid::Spacial::Document
+ include Mongoid::Geospatial
field :name, type: String
field :length, type: Integer
field :average_discharge, type: Integer
- field :source, type: Array, spacial: true
+ field :source, type: Point, spatial: true
# set return_array to true if you do not want a hash returned all the time
- field :mouth, type: Array, spacial: {lat: :latitude, lng: :longitude, return_array: true }
+ field :mouth, type: Point, spatial: {lat: :latitude, lng: :longitude, return_array: true }
+ field :course, type: Polygon
- # simplified spacial indexing
+ # simplified spatial indexing
# you can only index one point in mongodb version below 1.9
# if you want something besides the defaults {bit: 24, min: -180, max: 180} just set index to the options on the index
- spacial_index :source
+ spatial_index :source
end
```
+Avaiable data types:
+
+* Point
+* LineString
+* Polygon
+
+
Generate indexes on MongoDB:
```
@@ -41,7 +55,7 @@ rake db:mongoid:create_indexes
```
-Before we manipulate the data mongoid_spacial handles is what we call points.
+Before we manipulate the data mongoid_spatial handles is what we call points.
Points can be:
@@ -67,15 +81,15 @@ hudson = River.create(
mouth: {:latitude => 40.703056, :longitude => -74.026667}
)
-# now to access this spacial information we can now do this
+# now to access this spatial information we can now do this
hudson.source #=> {:lng => -73.935833, :lat => 44.106667}
hudson.mouth #=> [-74.026667, 40.703056] # notice how this returned as a lng,lat array because return_array was true
-# notice how the order of lng and lat were switched. it will always come out like this when using spacial.
+# notice how the order of lng and lat were switched. it will always come out like this when using spatial.
# Also adds a handy distance function
hudson.distance_from(:source, [-74,40], {:unit=>:mi})
```
-Mongoid Geo has extended all built in spacial symbol extentions
+Mongoid Geo has extended all built in spatial symbol extensions
* near
* River.where(:source.near => [-73.98, 40.77])
@@ -123,7 +137,7 @@ Post-Result has some advantages that are listed below.
# :page - pagination will be enabled if set to any variable including nil, pagination will not be enabled if either :per\_page or :paginator is set
# :per\_page
# :paginator - Choose which paginator to use. [default :arrary]
-# Prefered method to set is Mongoid::Spacial.paginator=:array
+# Prefered method to set is Mongoid::Geospatial.paginator=:array
# Available Paginators [:kaminari, :will\_paginate, :array]
# The only thing this does really is configure default per\_page so it is only kind of useful
River.geo_near([-73.99756,40.73083], :page => 1)
@@ -150,8 +164,152 @@ rivers = rivers.per(25).page(1)
rivers.reset! # resets the object to it is original state right after query.
```
+Mongo DB 1.9+ New Geo features
+---------
+
+Multi-location Documents v.1.9+
+
+MongoDB now also supports indexing documents by multiple locations. These locations can be specified in arrays of sub-objects, for example:
+
+```
+> db.places.insert({ addresses : [ { name : "Home", loc : [55.5, 42.3] }, { name : "Work", loc : [32.3, 44.2] } ] })
+> db.places.ensureIndex({ "addresses.loc" : "2d" })
+```
+
+Multiple locations may also be specified in a single field:
+
+```
+> db.places.insert({ lastSeenAt : [ { x : 45.3, y : 32.2 }, [54.2, 32.3], { lon : 44.2, lat : 38.2 } ] })
+> db.places.ensureIndex({ "lastSeenAt" : "2d" })
+```
+
+By default, when performing geoNear or $near-type queries on collections containing multi-location documents, the same document may be returned multiple times, since $near queries return ordered results by distance. Queries using the $within operator by default do not return duplicate documents.
+
+ v2.0
+In v2.0, this default can be overridden by the use of a $uniqueDocs parameter for geoNear and $within queries, like so:
+
+```
+> db.runCommand( { geoNear : "places" , near : [50,50], num : 10, uniqueDocs : false } )
+> db.places.find( { loc : { $within : { $center : [[0.5, 0.5], 20], $uniqueDocs : true } } } )
+```
+
+ Currently it is not possible to specify $uniqueDocs for $near queries
+Whether or not uniqueDocs is true, when using a limit the limit is applied (as is normally the case) to the number of results returned (and not to the docs or locations). If running a geoNear query with uniqueDocs : true, the closest location in a document to the center of the search region will always be returned - this is not true for $within queries.
+
+In addition, when using geoNear queries and multi-location documents, often it is useful to return not only distances, but also the location in the document which was used to generate the distance. In v2.0, to return the location alongside the distance in the geoNear results (in the field loc), specify includeLocs : true in the geoNear query. The location returned will be a copy of the location in the document used.
+
+ If the location was an array, the location returned will be an object with "0" and "1" fields in v2.0.0 and v2.0.1.
+
+```
+> db.runCommand({ geoNear : "places", near : [ 0, 0 ], maxDistance : 20, includeLocs : true })
+{
+ "ns" : "test.places",
+ "near" : "1100000000000000000000000000000000000000000000000000",
+ "results" : [
+ {
+ "dis" : 5.830951894845301,
+ "loc" : {
+ "x" : 3,
+ "y" : 5
+ },
+ "obj" : {
+ "_id" : ObjectId("4e52672c15f59224bdb2544d"),
+ "name" : "Final Place",
+ "loc" : {
+ "x" : 3,
+ "y" : 5
+ }
+ }
+ },
+ {
+ "dis" : 14.142135623730951,
+ "loc" : {
+ "0" : 10,
+ "1" : 10
+ },
+ "obj" : {
+ "_id" : ObjectId("4e5266a915f59224bdb2544b"),
+ "name" : "Some Place",
+ "loc" : [
+ [
+ 10,
+ 10
+ ],
+ [
+ 50,
+ 50
+ ]
+ ]
+ }
+ },
+ {
+ "dis" : 14.142135623730951,
+ "loc" : {
+ "0" : -10,
+ "1" : -10
+ },
+ "obj" : {
+ "_id" : ObjectId("4e5266ba15f59224bdb2544c"),
+ "name" : "Another Place",
+ "loc" : [
+ [
+ -10,
+ -10
+ ],
+ [
+ -50,
+ -50
+ ]
+ ]
+ }
+ }
+ ],
+ "stats" : {
+ "time" : 0,
+ "btreelocs" : 0,
+ "nscanned" : 5,
+ "objectsLoaded" : 3,
+ "avgDistance" : 11.371741047435734,
+ "maxDistance" : 14.142157540259815
+ },
+ "ok" : 1
+}
+```
+
+The plan is to include this functionality in a future release. Please help out ;)
+
+This Fork
+---------
+
+This fork is not backwards compatible with 'mongoid_spatial'.
+This fork delegates all the calculation to the nice RGeo.
+As a result, all the GEOS/Proj features are available in Ruby/Mongoid.
+
+Change in your models:
+
+ include Mongoid::Spacial::Document
+
+to
+
+ include Mongoid::Geospatial
+
+
+And for the fields:
+
+
+ field :source, type: Array, spacial: true
+
+to
+
+ field :source, type: Point, spatial: true
+
+
+Beware the 't' and 'c' issue. It's spaTial.
+
+
+
Troubleshooting
--------------
+---------------
**Mongo::OperationFailure: can't find special index: 2d**
@@ -163,7 +321,7 @@ Thanks
* Thanks to Kristian Mandrup for creating the base of the gem and a few of the tests
* Thanks to CarZen LLC. for letting me release the code we are using
-Contributing to mongoid_spacial
+Contributing to mongoid_spatial
-----------
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
View
24 lib/mongoid_geospatial.rb
@@ -0,0 +1,24 @@
+require 'rgeo'
+require 'mongoid'
+require 'active_support/core_ext/string/inflections'
+require 'active_support/concern'
+if Mongoid::VERSION > '3'
+ require 'mongoid_geospatial/contextual/mongo'
+else
+ require 'mongoid_geospatial/contexts/mongo'
+end
+require 'mongoid_geospatial/contextual/mongo'
+require 'mongoid_geospatial/criteria'
+require 'mongoid_geospatial/extensions/symbol'
+require 'mongoid_geospatial/extensions/rgeo_spherical_point_impl'
+require 'mongoid_geospatial/field_option'
+
+fields_path = 'mongoid_geospatial/fields' + (Mongoid::VERSION > '3' ? '' : '/mongoid2')
+
+%w{point polygon line_string}.each do |type|
+ require "#{fields_path}/#{type}"
+end
+
+require 'mongoid_geospatial/finders'
+require 'mongoid_geospatial/geospatial'
+
View
42 lib/mongoid_spacial/contexts/mongo.rb → lib/mongoid_geospatial/contexts/mongo.rb
@@ -19,7 +19,7 @@ class Mongo #:nodoc:
#
# Address.geo_near([70,40], :max_distance => 5, :unit => 5)
#
- # @param [ Array, Hash, #to_lng_lat ] center The center of where to calculate distance from
+ # @param [ Array, Hash, #to_xy ] center The center of where to calculate distance from
# @param [ Hash ] opts the options to query with
# @options opts [Integer] :num The number of rows to fetch
# @options opts [Hash] :query The query to filter the rows by, accepts
@@ -27,23 +27,24 @@ class Mongo #:nodoc:
# @options opts [Numeric] :max_distance The max distance of a row that should be returned in :unit(s)
# @options opts [Numeric, :km, :k, :mi, :ft] :unit automatically sets :distance_multiplier and converts :max_distance
# @options opts [true,false] :spherical Will determine the distance either by spherical calculation or flat calculation
- # @options opts [TrueClass,Array<Symbol>] :calculate Which extra fields to calculate distance for in ruby, if set to TrueClass it will calculate all spacial fields
+ # @options opts [TrueClass,Array<Symbol>] :calculate Which extra fields to calculate distance for in ruby, if set to TrueClass it will calculate all spatial fields
#
# @return [ Array ] Sorted Rows
def geo_near(center, opts = {})
opts = self.options.merge(opts)
# convert point
- center = center.to_lng_lat if center.respond_to?(:to_lng_lat)
+ center = center.to_xy if center.respond_to?(:to_xy)
+ center = [center.x, center.y] if center.respond_to?(:x)
# set default opts
opts[:skip] ||= 0
- if unit = Mongoid::Spacial.earth_radius[opts[:unit]]
- opts[:unit] = (opts[:spherical]) ? unit : unit * Mongoid::Spacial::RAD_PER_DEG
+ if unit = Mongoid::Geospatial.earth_radius[opts[:unit]]
+ opts[:unit] = (opts[:spherical]) ? unit : unit * Mongoid::Geospatial::RAD_PER_DEG
end
- if unit = Mongoid::Spacial.earth_radius[opts[:distance_multiplier]]
- opts[:distance_multiplier] = (opts[:spherical]) ? unit : unit * Mongoid::Spacial::RAD_PER_DEG
+ if unit = Mongoid::Geospatial.earth_radius[opts[:distance_multiplier]]
+ opts[:distance_multiplier] = (opts[:spherical]) ? unit : unit * Mongoid::Geospatial::RAD_PER_DEG
end
opts[:distance_multiplier] = opts[:unit] if opts[:unit].kind_of?(Numeric)
@@ -51,7 +52,7 @@ def geo_near(center, opts = {})
# setup paging.
if opts.has_key?(:page)
opts[:page] ||= 1
- opts[:paginator] ||= Mongoid::Spacial.paginator()
+ opts[:paginator] ||= Mongoid::Geospatial.paginator()
if opts[:per_page].blank?
opts[:per_page] = case opts[:paginator]
@@ -60,7 +61,7 @@ def geo_near(center, opts = {})
when :kaminari
Kaminari.config.default_per_page
else
- Mongoid::Spacial.default_per_page
+ Mongoid::Geospatial.default_per_page
end
opts[:per_page] = opts[:per_page].to_i
end
@@ -68,17 +69,16 @@ def geo_near(center, opts = {})
end
opts[:query] = create_geo_near_query(center,opts)
results = klass.db.command(opts[:query])
- Mongoid::Spacial::GeoNearResults.new(klass,results,opts)
+ Mongoid::Geospatial::GeoNearResults.new(klass,results,opts)
end
private
def create_geo_near_query(center,opts)
# minimum query
- query = {
- :geoNear => klass.collection_name,
- :near => center,
- }
+ query = BSON::OrderedHash.new
+ query[:geoNear] = klass.collection_name
+ query[:near] = center
# create limit and use skip
if opts[:num]
@@ -101,13 +101,15 @@ def create_geo_near_query(center,opts)
query['maxDistance'] = query['maxDistance']/opts[:unit].to_f if opts[:unit]
end
- if klass.db.connection.server_version >= '1.7'
- query['spherical'] = true if opts[:spherical]
-
- # 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
- # for mongodb < 1.7 we need to run Haversine first before calculating degrees to Km or Miles. See below.
- query['distanceMultiplier'] = opts[:distance_multiplier].to_f if opts[:distance_multiplier]
+ if opts[:unique_docs]
+ query['uniqueDocs'] = true
end
+
+ query['spherical'] = true if opts[:spherical]
+
+ # 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
+ # for mongodb < 1.7 we need to run Haversine first before calculating degrees to Km or Miles. See below.
+ query['distanceMultiplier'] = opts[:distance_multiplier].to_f if opts[:distance_multiplier]
query
end
end
View
117 lib/mongoid_geospatial/contextual/mongo.rb
@@ -0,0 +1,117 @@
+# encoding: utf-8
+module Mongoid #:nodoc:
+ module Contextual #:nodoc:
+ class Mongo #:nodoc:
+
+ # Fetches rows from the data base sorted by distance.
+ # In MongoDB versions 1.7 and above it returns a distance.
+ # Uses all criteria chains except without, only, asc, desc, order_by
+ #
+ # @example Minimal Query
+ #
+ # Address.geo_near([70,40])
+ #
+ # @example Chained Query
+ #
+ # Address.where(:state => 'ny').geo_near([70,40])
+ #
+ # @example Calc Distances Query
+ #
+ # Address.geo_near([70,40], :max_distance => 5, :unit => 5)
+ #
+ # @param [ Array, Hash, #to_xy ] center The center of where to calculate distance from
+ # @param [ Hash ] opts the options to query with
+ # @options opts [Integer] :num The number of rows to fetch
+ # @options opts [Hash] :query The query to filter the rows by, accepts
+ # @options opts [Numeric] :distance_multiplier this is multiplied against the calculated distance
+ # @options opts [Numeric] :max_distance The max distance of a row that should be returned in :unit(s)
+ # @options opts [Numeric, :km, :k, :mi, :ft] :unit automatically sets :distance_multiplier and converts :max_distance
+ # @options opts [true,false] :spherical Will determine the distance either by spherical calculation or flat calculation
+ # @options opts [TrueClass,Array<Symbol>] :calculate Which extra fields to calculate distance for in ruby, if set to TrueClass it will calculate all spatial fields
+ #
+ # @return [ Array ] Sorted Rows
+ def geo_near(center, opts = {})
+# opts = self.options.merge(opts)
+ # convert point
+ center = center.to_xy if center.respond_to?(:to_xy)
+ center = [center.x, center.y] if center.respond_to?(:x)
+
+ # set default opts
+ opts[:skip] ||= 0
+
+ if unit = Mongoid::Geospatial.earth_radius[opts[:unit]]
+ opts[:unit] = (opts[:spherical]) ? unit : unit * Mongoid::Geospatial::RAD_PER_DEG
+ end
+
+ if unit = Mongoid::Geospatial.earth_radius[opts[:distance_multiplier]]
+ opts[:distance_multiplier] = (opts[:spherical]) ? unit : unit * Mongoid::Geospatial::RAD_PER_DEG
+ end
+
+ opts[:distance_multiplier] = opts[:unit] if opts[:unit].kind_of?(Numeric)
+
+ # setup paging.
+ if opts.has_key?(:page)
+ opts[:page] ||= 1
+ opts[:paginator] ||= Mongoid::Geospatial.paginator()
+
+ if opts[:per_page].blank?
+ opts[:per_page] = case opts[:paginator]
+ when :will_paginate
+ @document.per_page
+ when :kaminari
+ Kaminari.config.default_per_page
+ else
+ Mongoid::Geospatial.default_per_page
+ end
+ opts[:per_page] = opts[:per_page].to_i
+ end
+
+ end
+ opts[:query] = create_geo_near_query(center,opts)
+ results = klass.mongo_session.command(opts[:query])
+ Mongoid::Geospatial::GeoNearResults.new(klass,results,opts)
+ end
+
+ private
+
+ def create_geo_near_query(center,opts)
+ # minimum query
+ query = {}
+ query[:geoNear] = klass.collection_name
+ query[:near] = center
+
+ # create limit and use skip
+ if opts[:num]
+ query['num'] = opts[:skip].to_i + opts[:num].to_i
+ elsif opts[:limit]
+ query['num'] = opts[:skip].to_i + opts[:limit].to_i
+ elsif opts[:page]
+ query['num'] = opts[:skip].to_i + (opts[:page].to_i * opts[:per_page].to_i)
+ end
+
+ # allow the use of complex werieis
+ if opts[:query]
+ query['query'] = self.criteria.where(opts[:query]).selector
+ elsif self.criteria.selector != {}
+ query['query'] = self.criteria.selector
+ end
+
+ if opts[:max_distance]
+ query['maxDistance'] = opts[:max_distance].to_f
+ query['maxDistance'] = query['maxDistance']/opts[:unit].to_f if opts[:unit]
+ end
+
+ if opts[:unique_docs]
+ query['uniqueDocs'] = true
+ end
+
+ query['spherical'] = true if opts[:spherical]
+
+ # 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
+ # for mongodb < 1.7 we need to run Haversine first before calculating degrees to Km or Miles. See below.
+ query['distanceMultiplier'] = opts[:distance_multiplier].to_f if opts[:distance_multiplier]
+ query
+ end
+ end
+ end
+end
View
10 lib/mongoid_geospatial/criteria.rb
@@ -0,0 +1,10 @@
+require 'mongoid_geospatial/criterion/complex'
+require 'mongoid_geospatial/criterion/near_spatial'
+require 'mongoid_geospatial/criterion/within_spatial'
+
+
+module Mongoid #:nodoc:
+ class Criteria
+ delegate :geo_near, :to => :context
+ end
+end
View
2  lib/mongoid_spacial/criterion/complex.rb → lib/mongoid_geospatial/criterion/complex.rb
@@ -10,7 +10,7 @@ module Criterion #:nodoc:
# becomes:
# <tt> { :field.lt => "value }</tt>
class Complex
-
+
def to_mongo_query v
{"$#{operator}" => v}
end
View
14 lib/mongoid_geospatial/criterion/inclusion.rb
@@ -0,0 +1,14 @@
+# encoding: utf-8
+# module Mongoid #:nodoc:
+# module Criterion #:nodoc:
+# module Inclusion
+# def near(attributes = {})
+# update_selector(attributes, "$near")
+# end
+
+# def near_sphere(attributes = {})
+# update_selector(attributes, "$near")
+# end
+# end
+# end
+# end
View
20 ...mongoid_spacial/criterion/near_spacial.rb → ...goid_geospatial/criterion/near_spatial.rb
@@ -6,28 +6,30 @@ module Criterion #:nodoc:
# get a shorthand syntax for where clauses.
#
# @example Coninputersion of a simple to complex criterion.
- # { :field => { "$nearSphere" => => [20,30]}, '$maxDistance' => 5 }
+ # { :field => { "$nearSphere" => [20,30]}, '$maxDistance' => 5 }
# becomes:
- # { :field.near(:sphere) => {:point => [20,30], :max => 5, :unit => :km} }
- class NearSpacial < Complex
+ # { :field.near_sphere => {:point => [20,30], :max => 5, :unit => :km} }
+ class NearSpatial < Complex
# Coninputert input to query for near or nearSphere
#
# @example
- # near = NearSpacial.new(:key => :field, :operator => "near")
+ # near = NearSpatial.new(:key => :field, :operator => "near")
# near.to_mongo_query({:point => [:50,50], :max => 5, :unit => :km}) => { '$near : [50,50]' , '$maxDistance' : 5 }
#
# @param [Hash,Array] input input to coninputer to query
def to_mongo_query(input)
- if input.kind_of?(Hash)
+ if input.respond_to?(:x)
+ {"$#{operator}" => [input.x, input.y]} #, '$maxDistance' => input[1] }
+ elsif input.kind_of?(Hash)
raise ':point required to make valid query' unless input[:point]
- input[:point] = input[:point].to_lng_lat if input[:point].respond_to?(:to_lng_lat)
+ input[:point] = input[:point].to_xy if input[:point].respond_to?(:to_xy)
query = {"$#{operator}" => input[:point] }
if input[:max]
query['$maxDistance'] = input[:max].to_f
- if unit = Mongoid::Spacial.earth_radius[input[:unit]]
- unit *= Mongoid::Spacial::RAD_PER_DEG unless operator =~ /sphere/i
+ if unit = Mongoid::Geospatial.earth_radius[input[:unit]]
+ unit *= Mongoid::Geospatial::RAD_PER_DEG unless operator =~ /sphere/i
input[:unit] = unit
end
@@ -38,7 +40,7 @@ def to_mongo_query(input)
if input.first.kind_of? Numeric
{"$#{operator}" => input }
else
- input[0] = input[0].to_lng_lat if input[0].respond_to?(:to_lng_lat)
+ input[0] = input[0].to_xy if input[0].respond_to?(:to_xy)
{"$#{operator}" => input[0], '$maxDistance' => input[1] }
end
end
View
20 ...ngoid_spacial/criterion/within_spacial.rb → ...id_geospatial/criterion/within_spatial.rb
@@ -9,33 +9,35 @@ module Criterion #:nodoc:
# { :field => { "$within" => {'$center' => [20,30]} } }
# becomes:
# { :field.within(:center) => [20,30] }
- class WithinSpacial < Complex
+ class WithinSpatial < Complex
# Convert input to query for box, polygon, center, and centerSphere
#
# @example
- # within = WithinSpacial.new(opts[:key] => 'point', :operator => 'center')
+ # within = WithinSpatial.new(opts[:key] => 'point', :operator => 'center')
# within.to_mongo_query({:point => [20,30], :max => 5, :unit => :km}) #=>
#
# @param [Hash,Array] input Variable to conver to query
def to_mongo_query(input)
- if ['box','polygon'].index(@operator)
+ if ['box','polygon'].include?(@operator)
input = input.values if input.kind_of?(Hash)
if input.respond_to?(:map)
- input.map!{ |v| (v.respond_to?(:to_lng_lat)) ? v.to_lng_lat : v }
+ input.map! do |v|
+ v.respond_to?(:to_xy) ? v.to_xy : v
+ end
else
input
end
- elsif ['center','centerSphere'].index(@operator)
+ elsif ['center','centerSphere'].include?(@operator)
if input.kind_of?(Hash) || input.kind_of?(ActiveSupport::OrderedHash)
raise ':point required to make valid query' unless input[:point]
- input[:point] = input[:point].to_lng_lat if input[:point].respond_to?(:to_lng_lat)
+ input[:point] = input[:point].to_xy if input[:point].respond_to?(:to_xy)
if input[:max]
input[:max] = input[:max].to_f
- if unit = Mongoid::Spacial.earth_radius[input[:unit]]
- unit *= Mongoid::Spacial::RAD_PER_DEG unless operator =~ /sphere/i
+ if unit = Mongoid::Geospatial.earth_radius[input[:unit]]
+ unit *= Mongoid::Geospatial::RAD_PER_DEG unless operator =~ /sphere/i
input[:unit] = unit
end
@@ -48,7 +50,7 @@ def to_mongo_query(input)
end
if input.kind_of? Array
- input[0] = input[0].to_lng_lat if input[0].respond_to?(:to_lng_lat)
+ input[0] = input[0].to_xy if input[0].respond_to?(:to_xy)
end
end
View
13 lib/mongoid_geospatial/extensions/rgeo_spherical_point_impl.rb
@@ -0,0 +1,13 @@
+module RGeo
+ module Geographic
+ class SphericalPointImpl
+ def to_a
+ [x, y, z]
+ end
+
+ def [] index
+ to_a[index]
+ end
+ end
+ end
+end
View
46 lib/mongoid_geospatial/extensions/symbol.rb
@@ -0,0 +1,46 @@
+# encoding: utf-8
+module Mongoid #:nodoc:
+ module Extensions #:nodoc:
+ module Symbol #:nodoc:
+
+ # return a class that will accept a value to convert the query correctly for near
+ #
+ # @param [Symbol] calc This accepts :sphere
+ #
+ # @return [Criterion::NearSpatial]
+
+ def near(calc = :flat)
+ Criterion::NearSpatial.new(:operator => get_op('near',calc), :key => self)
+ end
+
+ # alias for self.near(:sphere)
+ #
+ # @return [Criterion::NearSpatial]
+ def near_sphere
+ self.near(:sphere)
+ end
+
+ # @param [Symbol] shape :box,:polygon,:center,:center_sphere
+ #
+ # @return [Criterion::WithinSpatial]
+ def within(shape)
+ shape = get_op(:center,:sphere) if shape == :center_sphere
+ Criterion::WithinSpatial.new(:operator => shape.to_s , :key => self)
+ end
+
+ private
+
+ def get_op operator, calc
+ if calc.to_sym == :sphere
+ "#{operator}Sphere"
+ else
+ operator.to_s
+ end
+ end
+
+ end
+ end
+end
+
+
+::Symbol.__send__(:include, Mongoid::Extensions::Symbol)
View
16 lib/mongoid_geospatial/field_option.rb
@@ -0,0 +1,16 @@
+#require 'ostruct'
+
+Mongoid::Fields.option :spatial do |model,field,options|
+ options = {} unless options.kind_of?(Hash)
+ lat_meth = options[:lat] || :lat
+ lng_meth = options[:lng] || :lng
+ model.class_eval do
+ self.spatial_fields ||= []
+ self.spatial_fields << field.name.to_sym if self.spatial_fields.kind_of? Array
+
+ define_method "distance_from_#{field.name}" do |*args|
+ self.distance_from(field.name, *args)
+ end
+
+ end
+end
View
21 lib/mongoid_geospatial/fields/line_string.rb
@@ -0,0 +1,21 @@
+module Mongoid
+ module Geospatial
+ class LineString
+ # See http://mongoid.org/en/mongoid/docs/upgrading.html
+
+ def mongoize
+ to_a
+ end
+
+ class << self
+ def demongoize(object)
+ RGeo::Geographic.spherical_factory.line_string *object
+ end
+
+ # def evolve(object)
+ # { "$gte" => object.first, "$lte" => object.last }
+ # end
+ end
+ end
+ end
+end
View
20 lib/mongoid_geospatial/fields/mongoid2/line_string.rb
@@ -0,0 +1,20 @@
+module Mongoid
+ module Geospatial
+ class LineString
+ include Mongoid::Fields::Serializable
+
+ def self.instantiate name, options = {}
+ super
+ end
+
+ def serialize(object)
+ object.to_a
+ end
+
+ def deserialize(object)
+ return unless object && !object.empty?
+ RGeo::Geographic.spherical_factory.line_string(*object)
+ end
+ end
+ end
+end
View
20 lib/mongoid_geospatial/fields/mongoid2/point.rb
@@ -0,0 +1,20 @@
+module Mongoid
+ module Geospatial
+ class Point
+ include Mongoid::Fields::Serializable
+
+ def self.instantiate name, options = {}
+ super
+ end
+
+ def serialize(object)
+ object.respond_to?(:x) ? [object.x, object.y] : object
+ end
+
+ def deserialize(object)
+ return unless object && !object.empty?
+ RGeo::Geographic.spherical_factory.point *object
+ end
+ end
+ end
+end
View
23 lib/mongoid_geospatial/fields/mongoid2/polygon.rb
@@ -0,0 +1,23 @@
+module Mongoid
+ module Geospatial
+ class Polygon
+ include Mongoid::Fields::Serializable
+
+ def self.instantiate name, options = {}
+ super
+ end
+
+ def serialize(object)
+ object
+ end
+
+ def deserialize(object)
+ points = object.map do |pair|
+ RGeo::Geographic.spherical_factory.point *pair
+ end
+ ring = RGeo::Geographic.spherical_factory.linear_ring points
+ RGeo::Geographic.spherical_factory.polygon ring
+ end
+ end
+ end
+end
View
57 lib/mongoid_geospatial/fields/point.rb
@@ -0,0 +1,57 @@
+module Mongoid
+ module Geospatial
+ class Point
+ # See http://mongoid.org/en/mongoid/docs/upgrading.html
+
+ def mongoize
+ self.respond_to?(:x) ? [x, y] : self
+ # if object.respond_to? :x
+ # { "x" => object.x, "y" => object.y }
+ # else
+ # { "x" => object[0], "y" => object[1] }
+ # end
+ end
+
+ class << self
+
+ def demongoize(object)
+ return unless object && !object.empty?
+ RGeo::Geographic.spherical_factory.point *object
+ #["x"], object["y"]
+ end
+
+ # def evolve(object)
+ # { "$gte" => object.first, "$lte" => object.last }
+ # end
+ end
+
+# - self.spacial_fields ||= []
+# - self.spacial_fields << field.name.to_sym if self.spacial_fields.kind_of? Array
+# -
+# - define_method "distance_from_#{field.name}" do |*args|
+# - self.distance_from(field.name, *args)
+# - end
+# -
+# - define_method field.name do
+# - output = self[field.name] || [nil,nil]
+# - output = {lng_meth => output[0], lat_meth => output[1]} unless options[:return_array]
+# - return options[:class].new(output) if options[:class]
+# - output
+# - end
+# -
+# - define_method "#{field.name}=" do |arg|
+# - if arg.kind_of?(Hash) && arg[lng_meth] && arg[lat_meth]
+# - arg = [arg[lng_meth].to_f, arg[lat_meth].to_f]
+# - elsif arg.respond_to?(:to_xy)
+# - arg = arg.to_xy
+# - end
+# - self[field.name]=arg
+# - arg = [nil,nil] if arg.nil?
+# - return arg[0..1] if options[:return_array]
+# - h = {lng_meth => arg[0], lat_meth => arg[1]}
+# - return h if options[:class].blank?
+# - options[:class].new(h)
+
+ end
+ end
+end
View
25 lib/mongoid_geospatial/fields/polygon.rb
@@ -0,0 +1,25 @@
+module Mongoid
+ module Geospatial
+ class Polygon
+ # See http://mongoid.org/en/mongoid/docs/upgrading.html
+
+ def mongoize
+ self #.flatten
+ end
+
+ class << self
+ def demongoize(object)
+ points = object.map do |pair|
+ RGeo::Geographic.spherical_factory.point *pair
+ end
+ ring = RGeo::Geographic.spherical_factory.linear_ring points
+ RGeo::Geographic.spherical_factory.polygon ring
+ end
+
+ # def evolve(object)
+ # { "$gte" => object.first, "$lte" => object.last }
+ # end
+ end
+ end
+ end
+end
View
0  lib/mongoid_spacial/finders.rb → lib/mongoid_geospatial/finders.rb
File renamed without changes
View
90 lib/mongoid_geospatial/geospatial.rb
@@ -0,0 +1,90 @@
+require 'mongoid_geospatial/geospatial/core_ext'
+require 'mongoid_geospatial/geospatial/geo_near_results'
+
+module Mongoid
+ module Geospatial
+ extend ActiveSupport::Concern
+
+ LNG_SYMBOLS = [:x, :lon, :long, :lng, :longitude]
+ LAT_SYMBOLS = [:y, :lat, :latitude]
+
+ EARTH_RADIUS_KM = 6371 # taken directly from mongodb
+
+ EARTH_RADIUS = {
+ :km => EARTH_RADIUS_KM,
+ :m => EARTH_RADIUS_KM*1000,
+ :mi => EARTH_RADIUS_KM*0.621371192, # taken directly from mongodb
+ :ft => EARTH_RADIUS_KM*5280*0.621371192,
+ :sm => EARTH_RADIUS_KM*0.53995680345572 # sea mile
+ }
+
+ GEO_FACTORY = RGeo::Geographic.spherical_factory
+ RAD_PER_DEG = Math::PI/180
+ mattr_accessor :lng_symbols
+ @@lng_symbols = LNG_SYMBOLS.dup
+
+ mattr_accessor :lat_symbols
+ @@lat_symbols = LAT_SYMBOLS.dup
+
+ mattr_accessor :earth_radius
+ @@earth_radius = EARTH_RADIUS.dup
+
+ mattr_accessor :paginator
+ @@paginator = :array
+
+ mattr_accessor :default_per_page
+ @@default_per_page = 25
+
+ # mattr_accessor :spherical_distance_formula
+ # @@spherical_distance_formula = :n_vector
+ mattr_accessor :geo_factory
+ @@geo_factory = GEO_FACTORY.dup
+
+ included do
+ attr_accessor :geo
+ cattr_accessor :spatial_fields, :spatial_fields_indexed
+ @@spatial_fields = []
+ @@spatial_fields_indexed = []
+ end
+
+ module ClassMethods #:nodoc:
+ # create spatial index for given field
+ # @param [String,Symbol] name
+ # @param [Hash] options options for spatial_index
+
+ def spatial_index name, options = {}
+ self.spatial_fields_indexed << name
+ if Mongoid::VERSION =~ /3.0/
+ index({name => '2d'}, options)
+ else
+ index [[name, '2d']], options
+ end
+ end
+ end
+
+ # def distance(p2, opts = {})
+ # p1 = self.send(key)
+ # Mongoid::Geospatial.distance(p1, p2, opts)
+ # end
+
+
+
+ # def self.distance(p1,p2,opts = {})
+ # opts[:formula] ||= (opts[:spherical]) ? @@spherical_distance_formula : :pythagorean_theorem
+ # p1 = p1.to_lng_lat if p1.respond_to?(:to_lng_lat)
+ # p2 = p2.to_lng_lat if p2.respond_to?(:to_lng_lat)
+
+ # rads = Formulas.send(opts[:formula], p1, p2)
+
+ # if unit = earth_radius[opts[:unit]]
+ # opts[:unit] = (rads.instance_variable_get("@radian")) ? unit : unit * RAD_PER_DEG
+ # end
+
+ # rads *= opts[:unit].to_f if opts[:unit]
+ # rads
+
+ # end
+
+
+ end
+end
View
29 lib/mongoid_geospatial/geospatial/core_ext.rb
@@ -0,0 +1,29 @@
+class Array
+ def to_xy
+ self[0..1].map(&:to_f)
+ end
+ alias :to_lng_lat :to_xy
+end
+
+class Hash
+ def to_xy
+ raise "Hash must have at least 2 items" if self.size < 2
+ [to_x, to_y]
+ end
+ alias :to_lng_lat :to_xy
+
+ def to_y
+ v = (Mongoid::Geospatial.lat_symbols & self.keys).first
+ return self[v].to_f if !v.nil? && self[v]
+ raise "Hash must contain #{Mongoid::Geospatial.lat_symbols.inspect} if ruby version is less than 1.9" if RUBY_VERSION.to_f < 1.9
+ raise "Hash cannot contain #{Mongoid::Geospatial.lng_symbols.inspect} as the second item if there is no #{Mongoid::Geospatial.lat_symbols.inspect}" if Mongoid::Geospatial.lng_symbols.index(self.keys[1])
+ self.values[1].to_f
+ end
+
+ def to_x
+ v = (Mongoid::Geospatial.lng_symbols & self.keys).first
+ return self[v].to_f if !v.nil? && self[v]
+ raise "Hash cannot contain #{Mongoid::Geospatial.lat_symbols.inspect} as the first item if there is no #{Mongoid::Geospatial.lng_symbols.inspect}" if Mongoid::Geospatial.lat_symbols.index(self.keys[0])
+ self.values[0].to_f
+ end
+end
View
16 ...ngoid_spacial/spacial/geo_near_results.rb → ...geospatial/geospatial/geo_near_results.rb
@@ -1,11 +1,11 @@
module Mongoid
- module Spacial
+ module Geospatial
class GeoNearResults < Array
attr_reader :stats, :document, :_original_array, :_original_opts
attr_accessor :opts
def initialize(document,results,opts = {})
- raise "#{document.name} class must include Mongoid::Spacial::Document" unless document.respond_to?(:spacial_fields_indexed)
+ raise "#{document.name} class must include Mongoid::Geospatial::Document" unless document.respond_to?(:spatial_fields_indexed)
@document = document
@opts = opts
@_original_opts = opts.clone
@@ -23,12 +23,12 @@ def initialize(document,results,opts = {})
res.geo[key.snakecase.to_sym] = value
end
# dist_options[:formula] = opts[:formula] if opts[:formula]
- @opts[:calculate] = @document.spacial_fields_indexed if @document.spacial_fields_indexed.kind_of?(Array) && @opts[:calculate] == true
+ @opts[:calculate] = @document.spatial_fields_indexed if @document.spatial_fields_indexed.kind_of?(Array) && @opts[:calculate] == true
if @opts[:calculate]
@opts[:calculate] = [@opts[:calculate]] unless @opts[:calculate].kind_of? Array
@opts[:calculate] = @opts[:calculate].map(&:to_sym) & geo_fields
- if @document.spacial_fields_indexed.kind_of?(Array) && @document.spacial_fields_indexed.size == 1
- primary = @document.spacial_fields_indexed.first
+ if @document.spatial_fields_indexed.kind_of?(Array) && @document.spatial_fields_indexed.size == 1
+ primary = @document.spatial_fields_indexed.first
end
@opts[:calculate].each do |key|
res.geo[(key.to_s+'_distance').to_sym] = res.distance_from(key,center,{:unit =>@opts[:unit] || @opts[:distance_multiplier], :spherical => @opts[:spherical]} )
@@ -55,7 +55,7 @@ def page(*args)
def page!(page, options = {})
original = options.delete(:original)
self.opts.merge!(options)
- self.opts[:paginator] ||= Mongoid::Spacial.paginator
+ self.opts[:paginator] ||= Mongoid::Geospatial.paginator
self.opts[:page] = page
start = (self.current_page-1)*self.limit_value # assuming current_page is 1 based.
@@ -106,14 +106,14 @@ def limit_value
when :kaminari
Kaminari.config.default_per_page
else
- Mongoid::Spacial.default_per_page
+ Mongoid::Geospatial.default_per_page
end
end
end
alias_method :per_page, :limit_value
def num_pages
- (self.total_entries && @opts[:per_page]) ? (total_entries.to_f / @opts[:per_page]).ceil : nil
+ (total_entries && @opts[:per_page]) ? (total_entries.to_f / @opts[:per_page]).ceil : nil
end
alias_method :total_pages, :num_pages
View
5 lib/mongoid_geospatial/version.rb
@@ -0,0 +1,5 @@
+module Mongoid
+ module Geospatial
+ VERSION = "1.0.1"
+ end
+end
View
11 lib/mongoid_spacial.rb
@@ -1,11 +0,0 @@
-require 'mongoid'
-require 'active_support/core_ext/string/inflections'
-require 'active_support/concern'
-require 'mongoid_spacial/contexts/mongo'
-require 'mongoid_spacial/criteria'
-require 'mongoid_spacial/criterion'
-require 'mongoid_spacial/extentions/hash/criteria_helpers'
-require 'mongoid_spacial/extentions/symbol/inflections'
-require 'mongoid_spacial/field_option'
-require 'mongoid_spacial/finders'
-require 'mongoid_spacial/spacial'
View
5 lib/mongoid_spacial/criteria.rb
@@ -1,5 +0,0 @@
-module Mongoid #:nodoc:
- class Criteria
- delegate :geo_near, :to => :context
- end
-end
View
3  lib/mongoid_spacial/criterion.rb
@@ -1,3 +0,0 @@
-require 'mongoid_spacial/criterion/complex'
-require 'mongoid_spacial/criterion/near_spacial'
-require 'mongoid_spacial/criterion/within_spacial'
View
14 lib/mongoid_spacial/criterion/inclusion.rb
@@ -1,14 +0,0 @@
-# encoding: utf-8
-module Mongoid #:nodoc:
- module Criterion #:nodoc:
- module Inclusion
- def near(attributes = {})
- update_selector(attributes, "$near")
- end
-
- def near_sphere(attributes = {})
- update_selector(attributes, "$near")
- end
- end
- end
-end
View
22 lib/mongoid_spacial/extentions/hash/criteria_helpers.rb
@@ -1,22 +0,0 @@
-# encoding: utf-8
-module Mongoid #:nodoc:
- module Extensions #:nodoc:
- module Hash #:nodoc:
- module CriteriaHelpers #:nodoc:
- def expand_complex_criteria
- hsh = {}
- each_pair do |k,v|
- if k.respond_to?(:key) && k.respond_to?(:to_mongo_query)
- hsh[k.key] ||= {}
- hsh[k.key].merge!(k.to_mongo_query(v))
- else
- hsh[k] = v
- end
- end
- hsh
- end
- end
- end
- end
-end
-
View
46 lib/mongoid_spacial/extentions/symbol/inflections.rb
@@ -1,46 +0,0 @@
-# encoding: utf-8
-module Mongoid #:nodoc:
- module Extensions #:nodoc:
- module Symbol #:nodoc:
- module Inflections #:nodoc:
-
- # return a class that will accept a value to convert the query correctly for near
- #
- # @param [Symbol] calc This accepts :sphere
- #
- # @return [Criterion::NearSpacial]
-
- def near(calc = :flat)
- Criterion::NearSpacial.new(:operator => get_op('near',calc), :key => self)
- end
-
- # alias for self.near(:sphere)
- #
- # @return [Criterion::NearSpacial]
- def near_sphere
- self.near(:sphere)
- end
-
- # @param [Symbol] shape :box,:polygon,:center,:center_sphere
- #
- # @return [Criterion::WithinSpacial]
- def within(shape)
- shape = get_op(:center,:sphere) if shape == :center_sphere
- Criterion::WithinSpacial.new(:operator => shape.to_s , :key => self)
- end
-
- private
-
- def get_op operator, calc
- if calc.to_sym == :sphere && Mongoid.master.connection.server_version >= '1.7'
- "#{operator}Sphere"
- elsif calc.to_sym == :sphere
- raise "MongoDB Server version #{Mongoid.master.connection.server_version} does not have Spherical Calculation"
- else
- operator.to_s
- end
- end
- end
- end
- end
-end
View
38 lib/mongoid_spacial/field_option.rb
@@ -1,38 +0,0 @@
-require 'ostruct'
-# Field changes to Fields from mongoid 2.0 to mongoid 2.1
-field = (defined?(Mongoid::Field)) ? Mongoid::Field : Mongoid::Fields
-
-field.option :spacial do |model,field,options|
- options = {} unless options.kind_of?(Hash)
- lat_meth = options[:lat] || :lat
- lng_meth = options[:lng] || :lng
- model.class_eval do
- self.spacial_fields ||= []
- self.spacial_fields << field.name.to_sym if self.spacial_fields.kind_of? Array
-
- define_method "distance_from_#{field.name}" do |*args|
- self.distance_from(field.name, *args)
- end
-
- define_method field.name do
- output = self[field.name] || [nil,nil]
- output = {lng_meth => output[0], lat_meth => output[1]} unless options[:return_array]
- return options[:class].new(output) if options[:class]
- output
- end
-
- define_method "#{field.name}=" do |arg|
- if arg.kind_of?(Hash) && arg[lng_meth] && arg[lat_meth]
- arg = [arg[lng_meth].to_f, arg[lat_meth].to_f]
- elsif arg.respond_to?(:to_lng_lat)
- arg = arg.to_lng_lat
- end
- self[field.name]=arg
- arg = [nil,nil] if arg.nil?
- return arg[0..1] if options[:return_array]
- h = {lng_meth => arg[0], lat_meth => arg[1]}
- return h if options[:class].blank?
- options[:class].new(h)
- end
- end
-end
View
56 lib/mongoid_spacial/spacial.rb
@@ -1,56 +0,0 @@
-require 'mongoid_spacial/spacial/core_ext'
-require 'mongoid_spacial/spacial/formulas'
-require 'mongoid_spacial/spacial/document'
-require 'mongoid_spacial/spacial/geo_near_results'
-module Mongoid
- module Spacial
-
- EARTH_RADIUS_KM = 6371 # taken directly from mongodb
-
- EARTH_RADIUS = {
- :km => EARTH_RADIUS_KM,
- :m => EARTH_RADIUS_KM*1000,
- :mi => EARTH_RADIUS_KM*0.621371192, # taken directly from mongodb
- :ft => EARTH_RADIUS_KM*5280*0.621371192,
- }
-
- RAD_PER_DEG = Math::PI/180
-
- LNG_SYMBOLS = [:x, :lon, :long, :lng, :longitude]
- LAT_SYMBOLS = [:y, :lat, :latitude]
-
- def self.distance(p1,p2,opts = {})
- opts[:formula] ||= (opts[:spherical]) ? @@spherical_distance_formula : :pythagorean_theorem
- p1 = p1.to_lng_lat if p1.respond_to?(:to_lng_lat)
- p2 = p2.to_lng_lat if p2.respond_to?(:to_lng_lat)
-
- rads = Formulas.send(opts[:formula], p1, p2)
-
- if unit = earth_radius[opts[:unit]]
- opts[:unit] = (rads.instance_variable_get("@radian")) ? unit : unit * RAD_PER_DEG
- end
-
- rads *= opts[:unit].to_f if opts[:unit]
- rads
- end
-
- mattr_accessor :lng_symbols
- @@lng_symbols = LNG_SYMBOLS.dup
-
- mattr_accessor :lat_symbols
- @@lat_symbols = LAT_SYMBOLS.dup
-
- mattr_accessor :earth_radius
- @@earth_radius = EARTH_RADIUS.dup
-
- mattr_accessor :paginator
- @@paginator = :array
-
- mattr_accessor :default_per_page
- @@default_per_page = 25
-
- mattr_accessor :spherical_distance_formula
- @@spherical_distance_formula = :n_vector
-
- end
-end
View
27 lib/mongoid_spacial/spacial/core_ext.rb
@@ -1,27 +0,0 @@
-class Array
- def to_lng_lat
- self[0..1].map(&:to_f)
- end
-end
-
-class Hash
- def to_lng_lat
- raise "Hash must have at least 2 items" if self.size < 2
- [to_lng, to_lat]
- end
-
- def to_lat
- v = (Mongoid::Spacial.lat_symbols & self.keys).first
- return self[v].to_f if !v.nil? && self[v]
- raise "Hash must contain #{Mongoid::Spacial.lat_symbols.inspect} if ruby version is less than 1.9" if RUBY_VERSION.to_f < 1.9
- 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])
- self.values[1].to_f
- end
-
- def to_lng
- v = (Mongoid::Spacial.lng_symbols & self.keys).first
- return self[v].to_f if !v.nil? && self[v]
- 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])
- self.values[0].to_f
- end
-end
View
29 lib/mongoid_spacial/spacial/document.rb
@@ -1,29 +0,0 @@
-module Mongoid
- module Spacial
- module Document
- extend ActiveSupport::Concern
-
- included do
- attr_accessor :geo
- cattr_accessor :spacial_fields, :spacial_fields_indexed
- @@spacial_fields = []
- @@spacial_fields_indexed = []
- end
-
- module ClassMethods #:nodoc:
- # create spacial index for given field
- # @param [String,Symbol] name
- # @param [Hash] options options for spacial_index
- def spacial_index name, *options
- self.spacial_fields_indexed << name
- index [[ name, Mongo::GEO2D ]], *options
- end
- end
-
- def distance_from(key,p2, opts = {})
- p1 = self.send(key)
- Mongoid::Spacial.distance(p1, p2, opts)
- end
- end
- end
-end
View
52 lib/mongoid_spacial/spacial/formulas.rb
@@ -1,52 +0,0 @@
-module Mongoid
- module Spacial
- module Formulas
- class << self
- def n_vector(point1,point2)
- p1 = point1.map{|deg| deg * RAD_PER_DEG}
- p2 = point2.map{|deg| deg * RAD_PER_DEG}
-
- sin_x1 = Math.sin(p1[0])
- cos_x1 = Math.cos(p1[0])
-
- sin_y1 = Math.sin(p1[1])
- cos_y1 = Math.cos(p1[1])
-
- sin_x2 = Math.sin(p2[0])
- cos_x2 = Math.cos(p2[0])
-
- sin_y2 = Math.sin(p2[1])
- cos_y2 = Math.cos(p2[1])
-
- cross_prod = (cos_y1*cos_x1 * cos_y2*cos_x2) +
- (cos_y1*sin_x1 * cos_y2*sin_x2) +
- (sin_y1 * sin_y2)
-
- return cross_prod > 0 ? 0 : Math::PI if (cross_prod >= 1 || cross_prod <= -1)
-
- d = Math.acos(cross_prod)
- d.instance_variable_set("@radian", true)
- d
- end
-
- def haversine(point1,point2)
- p1 = point1.map{|deg| deg * RAD_PER_DEG}
- p2 = point2.map{|deg| deg * RAD_PER_DEG}
-
- dlon = p2[0] - p1[0]
- dlat = p2[1] - p1[1]
-
- a = (Math.sin(dlat/2))**2 + Math.cos(p1[1]) * Math.cos(p2[1]) * (Math.sin(dlon/2))**2
-
- d = 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a))
- d.instance_variable_set("@radian", true)
- d
- end
-
- def pythagorean_theorem(p1, p2)
- Math.sqrt(((p2[0] - p1[0]) ** 2) + ((p2[1] - p1[1]) ** 2))
- end
- end
- end
- end
-end
View
5 lib/mongoid_spacial/spacial/version.rb
@@ -1,5 +0,0 @@
-module Mongoid
- module Spacial
- VERSION = "0.2.16"
- end
-end
View
27 mongoid_geospatial.gemspec
@@ -0,0 +1,27 @@
+# -*- encoding: utf-8 -*-
+require File.expand_path('../lib/mongoid_geospatial/version', __FILE__)
+
+Gem::Specification.new do |gem|
+ gem.authors = ["Ryan Ong", "Marcos Piccinini"]
+ gem.email = ["use@git.hub.com"]
+ gem.description = %q{mongoid_geospatial simplifies spatial calculations. Adds integration into mongoid so pagination and other function continue to work. It adds symbol extensions to simplify query creation.}
+ gem.summary = %q{A Mongoid Extension that simplifies and adds support for MongoDB Geo Spatial Calculations.}
+ gem.homepage = "https://github.com/nofxx/mongoid_geospatial"
+
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ gem.files = `git ls-files`.split("\n")
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ gem.name = "mongoid_geospatial"
+ gem.require_paths = ["lib"]
+ gem.version = Mongoid::Geospatial::VERSION
+
+
+ gem.add_dependency('rgeo', ['>= 0.3.5'])
+ gem.add_dependency('mongoid', ['>= 2.0.0'])
+ gem.add_dependency('activesupport', ["~> 3.0"])
+ gem.add_development_dependency('yard', ["~>0.6.0"])
+ gem.add_development_dependency('rspec', ['~>2.3'])
+ gem.add_development_dependency('mocha', ['>= 0'])
+ gem.add_development_dependency('will_paginate', ['>= 0'])
+ gem.add_development_dependency('kaminari', ['>= 0'])
+end
View
27 mongoid_spacial.gemspec
@@ -1,27 +0,0 @@
-# -*- encoding: utf-8 -*-
-require File.expand_path('../lib/mongoid_spacial/spacial/version', __FILE__)
-
-Gem::Specification.new do |gem|
- gem.authors = ["Ryan Ong"]
- gem.email = ["ryanong@gmail.com"]
- gem.description = %q{mongoid_spacial simplifies spacial calculations. Adds integration into mongoid so pagination and other function continue to work. It adds symbol extentions to simplify query creation.}
- gem.summary = %q{A Mongoid Extention that simplifies and adds support for MongoDB Geo Spacial Calculations.}
- gem.homepage = "https://github.com/ryanong/mongoid_spacial"
-
- gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
- gem.files = `git ls-files`.split("\n")
- gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
- gem.name = "mongoid_spacial"
- gem.require_paths = ["lib"]
- gem.version = Mongoid::Spacial::VERSION
-
- gem.add_dependency("mongoid", ['>= 2.1.0'])
- gem.add_dependency('activesupport', ["~> 3.0"])
- gem.add_development_dependency('yard', ["~>0.6.0"])
- gem.add_development_dependency('rspec', ['~>2.3'])
- gem.add_development_dependency('rcov', ['>= 0'])
- gem.add_development_dependency('mocha', ['>= 0'])
- gem.add_development_dependency('will_paginate', ['>= 0'])
- gem.add_development_dependency('kaminari', ['>= 0'])
-
-end
View
18 spec/config/mongoid.yml
@@ -1,18 +0,0 @@
-test:
- database: mongoid_config_test
- host: localhost
- slaves:
- # - host: localhost
- # port: 27018
- # - host: localhost
- # port: 27019
- allow_dynamic_fields: false
- include_root_in_json: true
- parameterize_keys: false
- persist_in_safe_mode: false
- raise_not_found_error: false
- reconnect_time: 5
- autocreate_indexes: false
- persist_types: false
- option_no_exist: false
- skip_version_check: false
View
40 ...functional/mongoid/contexts/mongo_spec.rb → spec/functional/contexts/mongo_spec.rb
@@ -29,22 +29,23 @@
context ':maxDistance' do
it "should get 1 item" do
- Bar.geo_near(lax.location, :spherical => true, :max_distance => 2465/Mongoid::Spacial.earth_radius[:mi]).size.should == 1
+ Bar.geo_near(lax.location, :spherical => true, :max_distance => 2465/Mongoid::Geospatial.earth_radius[:mi]).size.should == 1
end
it "should get 2 items" do
- Bar.geo_near(lax.location, :spherical => true, :max_distance => 2480/Mongoid::Spacial.earth_radius[:mi]).size.should == 2
+ Bar.geo_near(lax.location, :spherical => true, :max_distance => 2480/Mongoid::Geospatial.earth_radius[:mi]).size.should == 2
end
end
context ':distance_multiplier' do
it "should multiply returned distance with multiplier" do
- 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)
+ Bar.geo_near(lax.location, :spherical => true, :distance_multiplier=> Mongoid::Geospatial.earth_radius[:mi]).second.geo[:distance].to_i.should be_within(1).of(2469)
end
end
context ':unit' do
it "should multiply returned distance with multiplier" do
+ pending
Bar.geo_near(lax.location, :spherical => true, :unit => :mi).second.geo[:distance].to_i.should be_within(1).of(2469)
end
@@ -76,13 +77,11 @@
it 'should limit 1' do
Bar.limit(1).geo_near(jfk.location).size.should == 1
end
-
end
-
end
context ':page' do
- before(:all) do
+ before do
Bar.delete_all
Bar.create_indexes
@@ -90,8 +89,9 @@
Bar.create({:location => [rand(360)-180,rand(360)-180]})
end
end
+
context ":paginator :array" do
- [nil,1,2].each do |page|
+ [nil,1,2].each do |page|
it "page=#{page} should have 25" do
Bar.geo_near([1,1], :page => page).size.should == 25
end
@@ -100,26 +100,36 @@
it "page=3 should have 0" do
Bar.geo_near([1,1], :page => 20).size.should == 0
end
-
+
it "per_page=5" do
Bar.geo_near([1,1], :page => 1, :per_page => 5).size.should == 5
end
end
- context ":paginator :kaminari" do
+ context ":paginator :kaminari" do
let(:near) {Bar.geo_near([1,1], :page => 1)}
- it "should have current_page" do
- near.current_page.should == 1
- end
- it "should have num_pages" do
- near.num_pages.should == 2
+ it 'should have 50 Bars' do
+ Bar.all.count.should == 50
end
it "should have limit_value" do
near.limit_value.should == 25
end
- end
+
+ # check results['results'] in GeoNearResults
+ it 'should find 25 items' do
+ near.size.should == 25
+ end
+
+ it "should have current_page" do
+ near.current_page.should == 1
+ end
+
+ it "should have num_pages" do
+ near.num_pages.should == 1
+ end
+ end
end
end
View
30 ...ional/mongoid/criterion/inclusion_spec.rb → spec/functional/criterion/inclusion_spec.rb
@@ -236,7 +236,7 @@
end
- context "Geo Spacial Complex Where" do
+ context "Geo Spatial Complex Where" do
let!(:home) do
[-73.98,40.77]
@@ -249,15 +249,15 @@
end
let!(:berlin) do
- Bar.create(:location => [ 52.30, 13.25 ])
+ Bar.create(:name => :berlin, :location => [ 52.30, 13.25 ])
end
let!(:prague) do
- Bar.create(:location => [ 50.5, 14.26 ])
+ Bar.create(:name => :prague, :location => [ 50.5, 14.26 ])
end
let!(:paris) do
- Bar.create(:location => [ 48.48, 2.20 ])
+ Bar.create(:name => :paris, :location => [ 48.48, 2.20 ])
end
it "returns the documents sorted closest to furthest" do
@@ -272,6 +272,10 @@
Bar.where(:location.near_sphere => [ 41.23, 2.9 ]).should == [ paris, prague, berlin ]
end
+ it "should find closest using rgeo point" do
+ Bar.where(:location.near => paris.location).to_a.should == [paris, berlin, prague]
+ end
+
end
context "#within" do
@@ -320,16 +324,16 @@
Bar.create(:name => 'mile1', :location => [-73.997345, 40.759382])
end
- let!(:mile3) do
- Bar.create(:name => 'mile2', :location => [-73.927088, 40.752151])
+ let!(:mile3) do
+ Bar.create(:name => 'mile2', :location => [-73.927088, 40.752151])
end
- let!(:mile7) do
- Bar.create(:name => 'mile3', :location => [-74.0954913, 40.7161472])
+ let!(:mile7) do
+ Bar.create(:name => 'mile3', :location => [-74.0954913, 40.7161472])
end
- let!(:mile11) do
- Bar.create(:name => 'mile4', :location => [-74.0604951, 40.9178011])
+ let!(:mile11) do
+ Bar.create(:name => 'mile4', :location => [-74.0604951, 40.9178011])
end
it "returns the documents within a center_sphere" do
@@ -337,15 +341,15 @@
end
it "returns the documents within a center_sphere" do
- Bar.where(:location.within(:center_sphere) => {:point => home,:max => 4, :unit => :mi}).should include(mile3)
+ Bar.where(:location.within(:center_sphere) => {:point => home,:max => 4, :unit => :mi}).should include(mile3)
end
it "returns the documents within a center_sphere" do
- Bar.where(:location.within(:center_sphere) => {:point => home,:max => 8, :unit => :mi}).should include(mile7)
+ Bar.where(:location.within(:center_sphere) => {:point => home,:max => 8, :unit => :mi}).should include(mile7)
end
it "returns the documents within a center_sphere" do
- Bar.where(:location.within(:center_sphere) => {:point => home,:max => 12, :unit => :mi}).should include(mile11)
+ Bar.where(:location.within(:center_sphere) => {:point => home,:max => 12, :unit => :mi}).should include(mile11)
end
end
end
View
14 .../mongoid/spacial/geo_near_results_spec.rb → ...ional/geospatial/geo_near_results_spec.rb
@@ -1,19 +1,16 @@
require "spec_helper"
-describe Mongoid::Spacial::GeoNearResults do
- before(:all) do
+describe Mongoid::Geospatial::GeoNearResults do
+ before do
Bar.delete_all
Bar.create_indexes
50.times do |i|
- Bar.create(:name => i.to_s, :location => [rand(358)-179,rand(358)-179])
+ Bar.create!(:name => i.to_s, :location => [rand(358)-179,rand(358)-179])
end
end
- before(:each) do
- while Bar.count < 50
- end
- end
+
context ":paginator :array" do
let(:bars) { Bar.geo_near([1,1]) }
@@ -70,7 +67,8 @@
near.limit_value.should == 25
end
end
-
+
+
context ":paginator :num_pages" do
it "when total=55 per=10 ,num_pages should be 6" do
5.times { |i| Bar.create(:name => i.to_s, :location => [rand(358)-179,rand(358)-179]) }
View
18 spec/functional/mongoid/spacial_spec.rb
@@ -1,18 +0,0 @@
-require "spec_helper"
-
-describe Mongoid::Spacial do
- describe '#distance' do
- it "should calculate 2d by default" do
- Mongoid::Spacial.distance([0,0],[3,4]).should == 5
- end
-
- it "should calculate 2d distances using degrees" do
- Mongoid::Spacial.distance([0,0],[3,4], :unit=>:mi).should == 5*Mongoid::Spacial::EARTH_RADIUS[:mi]*Mongoid::Spacial::RAD_PER_DEG
- end
-
- it "should calculate 3d distances by default" do
- Mongoid::Spacial.distance([-73.77694444, 40.63861111 ],[-118.40, 33.94],:unit=>:mi, :spherical => true).to_i.should be_within(1).of(2469)
- end
- end
-end
-
View
65 spec/functional/mongoid_geospatial_spec.rb
@@ -0,0 +1,65 @@
+require "spec_helper"
+
+describe Mongoid::Geospatial do
+
+ it "should instantiate with no problems" do
+ Bar.create!(name: "Moe's")
+ Bar.count.should eql(1)
+ end
+
+ it "should have a field mapped as point" do
+ bar = Bar.create!(location: [5,5])
+ bar.location.should be_a RGeo::Geographic::SphericalPointImpl
+ end
+
+ it "should have a .to_a" do
+ bar = Bar.create!(location: [3,2])
+ bar.location.to_a[0..1].should == [3.0, 2.0]
+ end
+
+ it "should have an array [] accessor" do
+ bar = Bar.create!(location: [3,2])
+ bar.location[0].should == 3.0
+ end
+
+
+ it "should accept an RGeo object" do
+ point = RGeo::Geographic.spherical_factory.point 1, 2
+ bar = Bar.create!(location: point)
+ bar.location.x.should be_within(0.1).of(1)
+ bar.location.y.should be_within(0.1).of(2)
+ end
+
+ it "should calculate distance between points" do
+ bar = Bar.create!(location: [5,5])
+ bar2 = Bar.create!(location: [15,15])
+ bar.location.distance(bar2.location).should be_within(1).of(1561283.8)
+ end
+
+ it "should calculate distance between points miles" do
+ pending
+ bar = Bar.create!(location: [5,5])
+ bar2 = Bar.create!(location: [15,15])
+ bar.location.distance(bar2.location).should be_within(1).of(1561283.8)
+ end
+
+ it "should calculate 3d distances by default" do
+ bar = Bar.create! location: [-73.77694444, 40.63861111 ]
+ bar2 = Bar.create! location: [-118.40, 33.94] #,:unit=>:mi, :spherical => true)
+ bar.location.distance(bar2.location).to_i.should be_within(1).of(2469)
+ end
+
+ it "should have a nice simple way to ovewrite geo factory" do
+ pending
+ bar = Bar.create!(location: [5,5])
+ bar2 = Bar.create!(location: [15,15])
+ bar.location.distance(bar2.location).should be_within(1).of(1561283.8)
+ end
+
+ it "should have a field mapped as polygon" do
+ farm = Farm.create!(area: [[5,5],[6,5],[6,6],[5,6]])
+ farm.area.should be_a RGeo::Geographic::SphericalPolygonImpl
+ end
+
+
+end
View
12 spec/models/bar.rb
@@ -1,9 +1,11 @@
class Bar
include Mongoid::Document
- include Mongoid::Spacial::Document
-
+ include Mongoid::Geospatial
+
field :name, :type => String
- field :location, :type => Array, :spacial => true
- references_one :rating, :as => :ratable
- spacial_index :location
+ field :location, :type => Point, :spatial => true
+
+ has_one :rating, :as => :ratable
+
+ spatial_index :location
end
View
10 spec/models/farm.rb
@@ -0,0 +1,10 @@
+class Farm
+ include Mongoid::Document
+ include Mongoid::Geospatial
+
+ field :name, :type => String
+ #field :location, :type => Point #, :spatial => true
+ field :area, :type => Polygon
+
+ #spatial_index :location
+end
View
18 spec/models/river.rb
@@ -1,20 +1,20 @@
class River
include Mongoid::Document
- include Mongoid::Spacial::Document
+ include Mongoid::Geospatial
field :name, type: String
field :length, type: Integer
field :average_discharge, type: Integer
- field :source, type: Array, spacial: true
+ field :source, type: Array, spatial: true
# set return_array to true if you do not want a hash returned all the time
- field :mouth, type: Array, spacial: {lat: 'latitude', lng: 'longitude'}
- field :mouth_array, type: Array, spacial: {return_array: true}
+ field :mouth, type: Array, spatial: {lat: 'latitude', lng: 'longitude'}
+ field :mouth_array, type: Array, spatial: {return_array: true}
- # simplified spacial indexing
+ # simplified spatial indexing
# you can only index one field in mongodb < 1.9
- spacial_index :source
+ spatial_index :source
# alternatives
- # index [[ :spacial, Mongo::GEO2D ]], {min:-400, max:400}
- # index [[ :spacial, Mongo::GEO2D ]], {bit:32}
- # index [[ :spacial, Mongo::GEO2D ],:name]
+ # index [[ :spatial, Mongo::GEO2D ]], {min:-400, max:400}
+ # index [[ :spatial, Mongo::GEO2D ]], {bit:32}
+ # index [[ :spatial, Mongo::GEO2D ],:name]
end
View
0  spec/unit/mongoid/criterion/complex_spec.rb → ...goid_geospatial/criterion/complex_spec.rb
File renamed without changes
View
0  .../unit/mongoid/criterion/inclusion_spec.rb → ...id_geospatial/criterion/inclusion_spec.rb
File renamed without changes
View
6 ...it/mongoid/criterion/near_spacial_spec.rb → ...geospatial/criterion/near_spatial_spec.rb
@@ -1,11 +1,11 @@
require "spec_helper"
-describe Mongoid::Criterion::NearSpacial do
+describe Mongoid::Criterion::NearSpatial do
let(:within) do
{
- :flat => Mongoid::Criterion::WithinSpacial.new(:key => :field, :operator => "near"),
- :sphere => Mongoid::Criterion::WithinSpacial.new(:key => :field, :operator => "nearSphere"),
+ :flat => Mongoid::Criterion::WithinSpatial.new(:key => :field, :operator => "near"),
+ :sphere => Mongoid::Criterion::WithinSpatial.new(:key => :field, :operator => "nearSphere"),
}
end
NEAR = {
View
54 spec/mongoid_geospatial/criterion/within_spatial_spec.rb
@@ -0,0 +1,54 @@
+require "spec_helper"
+
+describe Mongoid::Criterion::WithinSpatial do
+
+ let(:within) do
+ {
+ :box => Mongoid::Criterion::WithinSpatial.new(:key => :field, :operator => "box"),
+ :center => Mongoid::Criterion::WithinSpatial.new(:key => :field, :operator => "center"),
+ :polygon => Mongoid::Criterion::WithinSpatial.new(:key => :field, :operator => "polygon"),
+ :center_sphere => Mongoid::Criterion::WithinSpatial.new(:key => :field, :operator => "box"),
+ }
+ end
+
+ context "#to_mongo_query" do
+
+ {
+ :box =>
+ {
+ 'Array of Arrays' => [[10,20], [15,25]],
+ 'Array of Hashes' => [{ x: 10, y: 20 }, { x: 15, y: 25 }],
+ 'Hash of Hashes' => { a: { x: 10, y: 20 }, b: { x: 15, y: 25 }}
+ },
+ :polygon =>
+ {
+ 'Array of Arrays' => [[10,20], [15,25]],
+ 'Array of Hashes' => [{ x: 10, y: 20 }, { x: 15, y: 25 }],
+ 'Hash of Hashes' => { a: { x: 10, y: 20 }, b: { x: 15, y: 25 }}
+ },
+ :center =>
+ {
+ 'Point' => [[1,2],5],
+ 'Hash Point' => {:point => [-73.98, 40.77], :max => 5},
+ 'Hash Point Unit' => {:point => [-73.98, 40.77], :max => 5, :unit => :km}
+ },
+ :center_sphere =>
+ {
+ 'Point' => [[1,2],5],
+ 'Hash Point' => {:point => [-73.98, 40.77], :max => 5},
+ 'Hash Point Unit' => {:point => [-73.98, 40.77], :max => 5, :unit => :km}
+ }
+ }.each do |shape, points|
+
+ points.each do |input_name,input|
+
+ it "should generate a #{shape} query with '#{input_name}'" do
+ within[shape].to_mongo_query(input).should be_a_kind_of(Hash)
+ end
+
+ end
+ end
+
+ end # context
+end # describe
+
View
25 spec/mongoid_geospatial/geospatial_spec.rb
@@ -0,0 +1,25 @@
+require "spec_helper"
+
+describe Mongoid::Geospatial do
+
+ context "Class Stuff" do
+
+ it "should have an lng_symbols accessor" do
+ Mongoid::Geospatial.lng_symbols.should be_instance_of Array
+ Mongoid::Geospatial.lng_symbols.should include :x
+ end
+
+ it "should have an lat_symbols accessor" do
+ Mongoid::Geospatial.lat_symbols.should be_instance_of Array
+ Mongoid::Geospatial.lat_symbols.should include :y
+ end
+
+ end
+
+
+ context "Included" do
+ end
+
+
+
+end
View
34 spec/mongoid_setup.rb