Code Monkey home page Code Monkey logo

mongoid-geospatial's Introduction

Mongoid Geospatial

A Mongoid Extension that simplifies the use of MongoDB spatial features.

Gem Version Code Climate Coverage Status Build Status

Quick Start

This gem focuses on (making helpers for) MongoDB's spatial features using Mongoid 5, 6 and 7.

# Gemfile
gem 'mongoid-geospatial'

A Place to illustrate Point, Line and Polygon

class Place
  include Mongoid::Document

  # Include the module
  include Mongoid::Geospatial

  # Just like mongoid,
  field :name,     type: String

  # define your field, but choose a geometry type:
  field :location, type: Point
  field :route,    type: LineString
  field :area,     type: Polygon

  # To query on your points, don't forget to index:
  # You may use a method:
  sphere_index :location  # 2dsphere
  # or
  spatial_index :location # 2d

  # Or use a helper directly on the `field`:
  field :location, type: Point, spatial: true  # 2d
  # or
  field :location, type: Point, sphere: true   # 2dsphere
end

Generate indexes on MongoDB via rake:

rake db:mongoid:create_indexes

Or programatically:

Place.create_indexes

Points

This gem defines a specific Point class under the Mongoid::Geospatial namespace. Make sure to use type: ::Mongoid::Geospatial::Point to avoid name errors or collisions with other Point classes you might already have defined NameErrors.

Currently, MongoDB supports query operations on 2D points only, so that's what this lib does. All geometries apart from points are just arrays in the database. Here's is how you can input a point as:

  • longitude latitude array in that order - [long,lat] ([x, y])
  • an unordered hash with latitude key(:lat, :latitude) and a longitude key(:lon, :long, :lng, :longitude)
  • an ordered hash with longitude as the first item and latitude as the second item; this hash does not have include the latitude and longitude keys
  • anything with the a method #to_xy or #to_lng_lat that converts itself to [long, lat] array

Note: the convention of having longitude as the first coordinate may vary for other libraries. For instance, Google Maps often refer to "LatLng". Make sure you keep those differences in mind. See below for how to configure this library for LatLng.

We store data in the DB as a [x, y] array then reformat when it is returned to you

cafe = Place.create(
  name: 'Café Rider',
  location: {:lat => 44.106667, :lng => -73.935833},
  # or
  location: {latitude: 40.703056, longitude: -74.026667}
  #...

Now to access this spatial information we can do this

cafe.location  # => [-74.026667, 40.703056]

If you need a hash

cafe.location.to_hsh   # => { x: -74.026667, y: 40.703056 }

If you are using GeoRuby or RGeo

cafe.location.to_geo   # => GeoRuby::Point

cafe.location.to_rgeo  # => RGeo::Point

Conventions:

This lib uses #x and #y everywhere. It's shorter than lat or lng or another variation that also confuses. A point is a 2D mathematical notation, longitude/latitude is when you use that notation to map an sphere. In other words: all longitudes are 'xs' where not all 'xs' are longitudes.

Distance and other geometrical calculations are delegated to the external library of your choice. More info about using RGeo or GeoRuby below. Some built in helpers for mongoid queries:

# Returns middle point + radius
# Useful to search #within_circle
cafe.location.radius(5)        # [[-74.., 40..], 5]
cafe.location.radius_sphere(5) # [[-74.., 40..], 0.00048..]

# Returns hash if needed
cafe.location.to_hsh              # {:x => -74.., :y => 40..}
cafe.location.to_hsh(:lon, :lat)  # {:lon => -74.., :lat => 40..}

And for polygons and lines:

house.area.bbox    # Returns polygon bounding_box (envelope)
house.area.center  # Returns calculate middle point

Model Setup

You can create Point, Line, Circle, Box and Polygon on your models:

class CrazyGeom
  include Mongoid::Document
  include Mongoid::Geospatial

  field :location,  type: Point, spatial: true, delegate: true

  field :route,     type: Line
  field :area,      type: Polygon

  field :square,    type: Box
  field :around,    type: Circle

  # default mongodb options
  spatial_index :location, {bit: 24, min: -180, max: 180}

  # query by location
  spatial_scope :location
end

Helpers

You can use spatial: true to add a '2d' index automatically, No need for spatial_index :location:

field :location,  type: Point, spatial: true

And you can use sphere: true to add a '2dsphere' index automatically, no need for spatial_sphere :location:

field :location,  type: Point, sphere: true

You can delegate some point methods to the instance itself:

field :location,  type: Point, delegate: true

Now instead of instance.location.x you may call instance.x.

Nearby

You can add a spatial_scope on your models. So you can query:

Bar.nearby(my.location)

instead of

Bar.near(location: my.location)

Good when you're drunk. Just add to your model:

spatial_scope :<field>

Geometry

You can also store Circle, Box, Line (LineString) and Polygons. Some helper methods are available to them:

# Returns a geometry bounding box
# Useful to query #within_geometry
polygon.bbox
polygon.bounding_box

# Returns a geometry calculated middle point
# Useful to query for #near
polygon.center

# Returns middle point + radius
# Useful to search #within_circle
polygon.radius(5)        # [[1.0, 1.0], 5]
polygon.radius_sphere(5) # [[1.0, 1.0], 0.00048..]

Query

Before you proceed, make sure you have read this:

http://mongoid.github.io/old/en/origin/docs/selection.html#standard

All MongoDB queries are handled by Mongoid/Origin.

http://www.rubydoc.info/github/mongoid/origin/Origin/Selectable

You can use Geometry instance directly on any query:

  • near
Bar.near(location: person.house)
Bar.where(:location.near => person.house)
  • near_sphere
Bar.near_sphere(location: person.house)
Bar.where(:location.near_sphere => person.house)
  • within_polygon
Bar.within_polygon(location: [[[x,y],...[x,y]]])
# or with a bbox
Bar.within_polygon(location: street.bbox)
  • intersects_line
  • intersects_point
  • intersects_polygon

External Libraries

We currently support GeoRuby and RGeo. If you require one of those, a #to_geo and #to_rgeo, respectivelly, method(s) will be available to all spatial fields, returning the external library corresponding object.

Use RGeo?

https://github.com/dazuma/rgeo

RGeo is a Ruby wrapper for Proj/GEOS. It's perfect when you need to work with complex calculations and projections. It'll require more stuff installed to compile/work.

Use GeoRuby?

https://github.com/nofxx/georuby

GeoRuby is a pure Ruby Geometry Library. It's perfect if you want simple calculations and/or keep your stack in pure ruby. Albeit not full featured in maths it has a handful of methods and good import/export helpers.

Example

class Person
  include Mongoid::Document
  include Mongoid::Geospatial

  field :location, type: Point
end

me = Person.new(location: [8, 8])

# Example with GeoRuby
point.class # Mongoid::Geospatial::Point
point.to_geo.class # GeoRuby::SimpleFeatures::Point

# Example with RGeo
point.class # Mongoid::Geospatial::Point
point.to_rgeo.class # RGeo::Geographic::SphericalPointImpl

Configure

Assemble it as you need (use a initializer file):

With RGeo

Mongoid::Geospatial.with_rgeo!
# Optional
# Mongoid::Geospatial.factory = RGeo::Geographic.spherical_factory

With GeoRuby

Mongoid::Geospatial.with_georuby!

By default the convention of this library is LngLat, configure it for LatLng as follows.

Mongoid::Geospatial.configure do |config|
  config.point.x = Mongoid::Geospatial.lat_symbols
  config.point.y = Mongoid::Geospatial.lng_symbols
end

You will need to manually migrate any existing Point data if you change configuration in an existing system.

This Fork

This fork is not backwards compatible with 'mongoid_spacial'. This fork delegates calculations to external libs.

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 # or sphere: true

Beware the 't' and 'c' issue. It's spaTial.

Troubleshooting

Mongo::OperationFailure: can't find special index: 2d

Indexes need to be created. Execute command:

rake db:mongoid:create_indexes

Programatically

Model.create_indexes

Contributing

See CONTRIBUTING.

License

Copyright (c) 2009-2017 Mongoid Geospatial Authors

MIT License, see MIT-LICENSE.

mongoid-geospatial's People

Contributors

bitdeli-chef avatar dblock avatar gitter-badger avatar kristianmandrup avatar maddijoyce avatar nofxx avatar ryanong avatar startouf avatar supernova23 avatar tagliala avatar undr avatar victorhg avatar wdbmh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

mongoid-geospatial's Issues

Feature request: Programmatic index creation

I've been using this gem in an engine. Unfortunately I can't run the Mongoid rake tasks from within an engine spec suite, only from within a real Rails app it seems :(

From https://github.com/mongoid/mongoid/blob/master/lib/mongoid/railties/database.rake

      engines_models_paths = Rails.application.railties.engines.map do |engine|
        engine.paths["app/models"].expanded
      end
      root_models_paths = Rails.application.paths["app/models"]
      models_paths = engines_models_paths.push(root_models_paths).flatten

      models_paths.each do |path|
        ::Rails::Mongoid.create_indexes("#{path}/**/*.rb")
      end

Would be nice to encapsulate this in a method that is easy to use even outside of Rails, perhaps just sending it a list of paths:

module Mongoid
  module Indexing
    class << self
      def create_indexes models_paths = nil
        models_paths ||= rails_models_paths

        raise ArgumentError, "No model paths for creating mongoid indexes" if models_paths.blank?
        puts "CREATE INDEXES: #{models_paths}"

        models_paths.each do |path|
          ::Rails::Mongoid.create_indexes("#{path}/**/*.rb")
        end
      end

      def remove_indexes models_paths = nil
        models_paths ||= rails_models_paths

        raise ArgumentError, "No model paths for creating mongoid indexes" if models_paths.blank?
        puts "REMOVING INDEXES: #{models_paths}"

        models_paths.each do |path|
          ::Rails::Mongoid.remove_indexes("#{path}/**/*.rb")
        end
      end

      def rails_models_paths
        engines_models_paths = Rails.application.railties.engines.map do |engine|
          engine.paths["app/models"].expanded
        end
        root_models_paths = Rails.application.paths["app/models"]
        engines_models_paths.push(root_models_paths).flatten
      end          
    end
  end
end

Used this in my engine and it works beautifully :)

What do you think?

Here a snapshot of my code to generate random data in the vicinity in order to test a near search ;)

    def base_pos
      [longitude, latitude]
    end

    def longitude
      55.6760968
    end

    def latitude
      12.5683371
    end

    def random_point_within distance
      vector = random_vector(distance)
      (base_pos.geo_point + vector).to_lng_lat
    end

    def random_vector distance
      [distance, 0].vector.random_vector
    end

    # RANDOM PROPERTIES
    before :all do
      10.times do
        SearchableProperty.create type: 'apartment', 
          rooms: rand(6)+1, size: rand(100)+10, country_code: 'DK', 
          position: random_point_within(10.kms)
      end

      Mongoid::Indexing.create_indexes
      # puts SearchableProperty.all.map(&:inspect)
    end

RGeo default factory cannot be set

module Geospatial
# Wrapper to Rgeo's Point
Point.class_eval do
#
# With RGeo support
#
# @return (RGeo::SphericalFactory::Point)
def to_rgeo
RGeo::Geographic.spherical_factory.point x, y
end

Here, and everywhere else, the spherical_factory is being used to convert geometries from geospatial Objects into RGeos objects. However, this may not always be the best choice.

The library geo_json already has a solution, that may serve as a guide:

https://github.com/rgeo/rgeo-geojson/blob/6c76aced209969692a51364d6765b45c61eabf08/lib/rgeo/geo_json/coder.rb#L23-L24

error when requiring georuby

in mongoid_geospatial / lib / mongoid_geospatial / wrappers / georuby.rb there's this:

require 'georuby'

but the georuby gem still has geo_ruby filenames, so it fails the require

License missing from gemspec

(this is a cut and paste from a script that found my repository)

Some companies will only use gems with a certain license.
The canonical and easy way to check is via the gemspec
via e.g.

spec.license = 'MIT'
# or
spec.licenses = ['MIT', 'GPL-2']

There is even a License Finder to help companies ensure all gems they use
meet their licensing needs. This tool depends on license information being available in the gemspec.
Including a license in your gemspec is a good practice, in any case.

External (Geom) Libs

Came to two approaches:

Have Mongoid::Geospatial own Point, Polygon and LineString classes

pro: avoids cpu waste, no ifs to check which lib, and in MongoDB supported criteria for instance you won't be instantiating a RGeo or GeoRuby object just to make it an array again later.

Use a separate method to get the external lib object (#to_geo)

pro: same as the above, no ifs, everywhere it's not needed no cycles are wasted.

Solution for now:

Need to require "mongoid_geospatial_(rgeo or georuby)"

cons: single file to hold it all? another approach?

license file

readme states:

Copyright (c) 2011 Ryan Ong. See LICENSE.txt for further details.

but no license file is provided. Is this gem released under the MIT license as the original one?

TIA

Transfer mongoid-geospatial to github.com/mongoid

I had https://github.com/mongoid kindly donated to the community by the nice folks at MongoDB. The three people who have org level admin access are currently @durran, @estolfo and myself.

I want to invite this project to be moved to the org. I think it makes good sense to group mongoid projects together and have continuous support from MongoDB, the company, over the long term. All admins of this project will continue having admin access of course, but this would reduce the bus factor since currently only @nofxx can add maintainers here.

If you think it's a good idea, please transfer this project to me and I'll move it into the org and please add [email protected], [email protected] and [email protected] to rubygems.

Support for new Geo features in Mongo DB 2.3+

Very exciting new Geo features!! :)

http://docs.mongodb.org/manual/release-notes/2.4/#new-geospatial-indexes-with-geojson-and-improved-spherical-geometry

The 2.3 series adds a new type of geospatial index that supports improved spherical queries and GeoJSON. Create the index by specifying 2dsphere as the value of the field in the index specification, as any of the following:

db.collection.ensureIndex( { geo: "2dsphere" } )
db.collection.ensureIndex( { type: 1, geo: "2dsphere" } )
db.collection.ensureIndex( { geo: "2dsphere", type: 1 } )

In the first example you create a spherical geospatial index on the field named geo, in the second example, you create a compound index where the first field is a normal index, and the index of the second field is a spherical geospatial index. Unlike 2d indexes, fields indexed using the 2dsphere type do not have to be the first field in a compound index.

You must store data in the fields indexed using the 2dsphere index using the GeoJSON specification, at the moment. Support for storing points, in the form used by the existing 2d (i.e. geospatial) indexes is forthcoming. Currently, 2dsphere indexes only support the following GeoJSON shapes:

Point, as in the following:

{ "type": "Point", "coordinates": [ 40, 5 ] }

LineString, as in the following:

`{ "type": "LineString", "coordinates": [ [ 40, 5 ], [ 41, 6 ] ] }``

Polygon, as in the following:

{
  "type": "Polygon",
  "coordinates": [ [ [ 40, 5 ], [ 40, 6 ], [ 41, 6 ], [ 41, 5 ], [ 40, 5 ] ] ]
}

To query 2dsphere indexes, all current geospatial query operators with an additional $geoIntersects operator. Currently, all queries using the 2dsphere index must pass the query selector (e.g. $near, $geoIntersects) a GeoJSON document. With the exception of the GeoJSON requirement, the operation of $near is the same for 2dsphere indexes as 2d indexes.

$geoIntersects

The $geoIntersects selects all indexed points that intersect with the provided geometry. (i.e. Point, LineString, and Polygon.) You must pass $geoIntersects a document in GeoJSON format.

db.collection.find( { loc: { $geoIntersects:
                             { $geometry: { "type": "Point",
                                            "coordinates": [ 40, 5 ]
                             } } } } )

Would be nice to have initial support for this in the gem (or perhaps in mongoid_spatial) !?

Rails 4 and Mongoid 4 support

In gemspec

  gem.add_dependency('activesupport', ["~> 3.2"])
  gem.add_development_dependency('yard', ["~>0.6.0"])
  gem.add_development_dependency('rspec', ['~>2.11'])

Update dependencies to be more open/flexible, sth like:

  gem.add_dependency('activesupport', [">= 3.2"])
  gem.add_development_dependency('yard', [">=0.6.0"])
  gem.add_development_dependency('rspec', ['>=2.11'])

I would think?

make rgeo gem dependency optional

According to your README, I can choose from either rgeo or georuby. Actually rgeo is a dependency for mongoid_geospatial gem.

It might be very cleaner to let the user choose what gem to use.

Multiple Points Helper

Basically, the only method the old spacial had we are missing is Class#near.

This has one issue to be discussed: what if the class in question has 2 geom indexed.
Supposing a class Bar with 2 points: 'a' and 'b'

Option 1 only the first (or last) field is used:

Bar.near [1,1]
# Bar.where(a: [1,1])

Option 2 both fields is used:

Bar.near [1,1]
# Bar.where(a: [1,1], b: [1,1])

Option 3 another option the field to set the 'main searchable point'

field :b,  type: Point,  spatial: true,  exclusive: true
Bar.near [1,1]
# Bar.where(b: [1,1])

1, 2, 3 or comment 4.

Cannot use within_polygon

Hi, I'm not sure what I am doing wrong, but I am not able to use the within_polygon method.
I have a class, Complaint, which is set up like so:

class Complaint
  include Mongoid::Document
  include Mongoid::Geospatial
  include Mongoid::Timestamps::Short
  field :title
  field :description
  field :location, type: Point
  field :images, type: Array
  field :resolved, type: Boolean, default: false
  field :needs_moderation, type: Boolean, default: false
  belongs_to :complaint_type
  belongs_to :user
  has_many :comments
  has_many :likes, as: :feedbackable
  has_many :dislikes, as: :feedbackable
  has_many :moderation_requests

  validates_presence_of :title, :description

  attr_accessor :distance

  spatial_index :location, {min: -200, max: 200}

  spatial_scope :location

  scope :created_after, -> (datetime) {where(:c_at.gte => datetime)}
  scope :created_before, -> (datetime) {where(:c_at.lte => datetime)}
  scope :created_between, -> (start_time, end_time) {created_after(start_time).created_before(end_time)}

When I do Complaint.within_polygon(location: [[[1, 0], [1, 1], [0, 3]]]), I get

NoMethodError: undefined method `within_polygon' for Complaint:Class
Did you mean?  with_options
	from (irb):3
	from /Users/utkarshdalal/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/console.rb:65:in `start'
	from /Users/utkarshdalal/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/console_helper.rb:9:in `start'
	from /Users/utkarshdalal/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/commands_tasks.rb:78:in `console'
	from /Users/utkarshdalal/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
	from /Users/utkarshdalal/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/railties-5.0.0.1/lib/rails/commands.rb:18:in `<top (required)>'
	from bin/rails:4:in `require'
	from bin/rails:4:in `<main>'

What am I doing wrong?

Artificial limit on Polygons

I'm trying to load in some polygons from a shapefile which has coordinates stored in Ordnance Survey Easting and Northings. I run the code below and it seems to work (in that I get no errors), but then it appears that nothing has saved:

GeoRuby::Shp4r::ShpFile.open(file) do |shp|
  shp.each do |shape|
    name = shape.data['NAME']
    code = shape.data['UNIT_ID']
    geom = shape.geometry.to_coordinates

    Boundary.create(:name  => name,
                    :code  => code,
                    :type  => type,
                    :shape => geom
                    )
  end
end

After some experimentation, it seems that coordinates are limited to two digits (I'm assuming there's an assumption made that coords will be Latitude and Longitude), but I get no errors. Is this a limitation in MongoDB, or an artificial limit that's been introduced this end? Or (and it's quite possible here), am I doing something really stupid?

Here's my model for reference too:

class Boundary
  include Mongoid::Document
  include Mongoid::Geospatial

  field :name, type: String
  field :code, type: String
  field :type, type: String
  field :shape, type: Polygon

  spatial_index :shape
end

Storing polygons as array is messing with $geoIntersects

When storing a polygon field as array, searching all points within the polygon, as well as intersecting 2 polygons works.

But finding all polygons including a particular point does not work when the polygon field is an array, and seems to works only when the polygon is store as GeoJSON object.

To reproduce:

db.geom.insert({"polygons":
  {"type":"Polygon",
     coordinates:
      [[[ 17.60083012593064, 78.18557739257812], 
        [ 17.16834652544664, 78.19381713867188], 
        [ 17.17490690610013, 78.739013671875], 
        [ 17.613919673106714, 78.73489379882812],
        [ 17.60083012593064, 78.18557739257812]
      ]]
  }, "coo": [[ 17.60083012593064, 78.18557739257812], 
        [ 17.16834652544664, 78.19381713867188], 
        [ 17.17490690610013, 78.739013671875], 
        [ 17.613919673106714, 78.73489379882812],
        [ 17.60083012593064, 78.18557739257812]
      ]
}); 

This works

db.geom.find({polygons:
  {$geoIntersects:
     {$geometry:{ "type" : "Point",
          "coordinates" : [ 17.3734, 78.4738 ] }
      }
  }
});

This does not work

db.geom.find({coo:
  {$geoIntersects:
     {$geometry:{ "type" : "Point",
          "coordinates" : [ 17.3734, 78.4738 ] }
      }
  }
});

A solution is to store the polygon as a geoJSON object.
Is there any reason it's stored as a plain array, or is it safe to migrate all the geo field to GeoJSON object ?

Lat and Lng rounding?

Hi there,
using the gem with mongoid (latest stable) and i am sending lat and lng from a from with a bunch of numbers after the floating point. e.g:

    "location"=>{"x"=>"34.872818406745864", "y"=>"31.929971507732105"}

As a result, the mongo record is saved by with a less accurate float:

    "34.8728345, 31.9292203"

It basically means that i am loosing accuracy on a map selected point. ideas?

Problem when try to return a Polygon from database

the model

class Delivery
  class Zone
    include Mongoid::Document
    include Mongoid::Timestamps
    include Mongoid::Geospatial

    field :area, type: Polygon, sphere: true
  end
end

creating an area

area = Mongoid::Geospatial::Polygon.new([[-46.74579620361328, -23.526297058421182],[-46.723995208740234, -23.548172777916854],[-46.707258224487305,-23.529917032960597],[-46.725196838378906,-23.517167984845393],[-46.74579620361328,-23.526297058421182]])

json = {'type': 'Polygon', coordinates: [area]}

Delivery::Zone.create(area: json)

On MongoDB

> db.delivery_zones.find().pretty()
{
  "_id" : ObjectId("57684889ae61d11b5ec5c992"),
  "area" : {
    "type" : "Polygon",
    "coordinates" : [
      [
        [
          -46.62915229797363,
          -23.575944975344676
        ],
        [
          -46.630589962005615,
          -23.58227747294
        ],
        [
          -46.62475347518921,
          -23.582965769489153
        ],
        [
          -46.62292957305908,
          -23.577046301216768
        ],
        [
          -46.62915229797363,
          -23.575944975344676
        ]
      ]
    ]
  }
}

Executing on rails c

Delivery::Zone.last.area

TypeError: no implicit conversion of BSON::Document into Integer
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/mongoid-geospatial-5.0.0/lib/mongoid/geospatial/geometry_field.rb:86:in `initialize'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/mongoid-geospatial-5.0.0/lib/mongoid/geospatial/geometry_field.rb:86:in `new'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/mongoid-geospatial-5.0.0/lib/mongoid/geospatial/geometry_field.rb:86:in `demongoize'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/mongoid-5.1.3/lib/mongoid/fields/standard.rb:10:in `demongoize'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/mongoid-5.1.3/lib/mongoid/fields.rb:418:in `block (2 levels) in create_field_getter'
    from (irb):3
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/railties-4.2.6/lib/rails/commands/console.rb:110:in `start'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/railties-4.2.6/lib/rails/commands/console.rb:9:in `start'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/railties-4.2.6/lib/rails/commands/commands_tasks.rb:68:in `console'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/railties-4.2.6/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/railties-4.2.6/lib/rails/commands.rb:17:in `<top (required)>'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.6/lib/active_support/dependencies.rb:274:in `require'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.6/lib/active_support/dependencies.rb:274:in `block in require'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.6/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.6/lib/active_support/dependencies.rb:274:in `require'
    from /Users/marco/Documents/prj/zipster/ecommerce/src/bin/rails:9:in `<top (required)>'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.6/lib/active_support/dependencies.rb:268:in `load'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.6/lib/active_support/dependencies.rb:268:in `block in load'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.6/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/activesupport-4.2.6/lib/active_support/dependencies.rb:268:in `load'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/commands/rails.rb:6:in `call'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/command_wrapper.rb:38:in `call'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:191:in `block in serve'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:161:in `fork'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:161:in `serve'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:131:in `block in run'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:125:in `loop'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application.rb:125:in `run'
    from /Users/marco/.rvm/gems/ruby-2.3.1/gems/spring-1.7.1/lib/spring/application/boot.rb:19:in `<top (required)>'
    from /Users/marco/.rvm/rubies/ruby-2.3.1/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from /Users/marco/.rvm/rubies/ruby-2.3.1/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from -e:1:in `<main>'

I changed the line 86 of geometry_field.rb from:

        def demongoize(obj)
          obj && new(obj)
        end

to

        def demongoize(obj)
          obj
        end

And apparently worked.
Question: Why we have the '&& new(obj)'?
Thank you,
Marco.

Anything to add?

Every function the old spacial had is here, with the exception of distance, which is delegated to external libraries. And some new cool stuff like bbox and new geometry types.

Now it's time to try and think what can be improved. Waiting for suggestions.

Spec errors

In order to make the specs run, I had to add a test group to Gemfile:

group :test do
  gem 'dbf'
  gem 'nokogiri'
end
kmandrup:mongoid_geospatial (master) $ bspec spec/
Running with Mongoid v3.0.6
/Users/kmandrup/private/repos/mongoid_geospatial/spec/mongoid_geospatial/wrappers/georuby_spec.rb:2: warning: already initialized constant Point
...................................................F.F....

Failures:

  1) Mongoid::Geospatial::Point queryable (de)mongoize should calculate 3d distances by default
     Failure/Error: bar.location.distance(bar2.location.to_geo).to_i.should be_within(1).of(3978262)
     NoMethodError:
       undefined method `distance' for #<GeoRuby::SimpleFeatures::Point:0x007fafeab79340>
     # ./lib/mongoid_geospatial/wrappers/georuby.rb:8:in `distance'
     # ./spec/mongoid_geospatial/wrappers/georuby_spec.rb:51:in `block (4 levels) in <top (required)>'

  2) Mongoid::Geospatial::Point should not respond to distance before loading external
     Failure/Error: bar.location.should_not respond_to(:distance)
       expected #<Mongoid::Geospatial::Point:0x007fafec2c37f8 @x=5.0, @y=5.0> not to respond to :distance
     # ./spec/mongoid_geospatial/wrappers/rgeo_spec.rb:12:in `block (2 levels) in <top (required)>'

Finished in 1.64 seconds
58 examples, 2 failures

Failed examples:

rspec ./spec/mongoid_geospatial/wrappers/georuby_spec.rb:48 # Mongoid::Geospatial::Point queryable (de)mongoize should calculate 3d distances by default
rspec ./spec/mongoid_geospatial/wrappers/rgeo_spec.rb:10 # Mongoid::Geospatial::Point should not respond to distance before loading external

Rails 4?

Is there any plan for Rails 4 support?

Bundler could not find compatible versions for gem "activemodel":
  In Gemfile:
    mongoid_geospatial (>= 0) ruby depends on
      activemodel (~> 3.1) ruby

    rails (= 4.0.0) ruby depends on
      activemodel (4.0.0)

Passing a hash with string symbols does not work

When trying to create a Point via the Hash method, I cannot use string symbols to do so. This is a particular problem when setting Lat/Long values from a form in Rails.

These tests illustrate the problem:

    # PASSES
    it "should mongoize hash with symbols in any order" do
      geom = Bar.new(location: {y: -9, x: 10}).location
      geom.class.should eql(Mongoid::Geospatial::Point)
      geom.x.should be_within(0.1).of(10)
      geom.y.should be_within(0.1).of(-9)
    end

    # FAILS
    it "should mongoize hash with string keys in any order" do
      geom = Bar.new(location: {'y' => -9, 'x' => 10}).location
      geom.class.should eql(Mongoid::Geospatial::Point)
      geom.x.should be_within(0.1).of(10)
      geom.y.should be_within(0.1).of(-9)
    end

When using string keys in a Hash, the keys 'x' and 'y' are not recognized as valid keys and the behavior reverts to expecting an ordered Hash (longitude first, latitude second).

A "delegate" problem

I get "undefined method `[]' for nil:NilClass" when using .x or .y methods on an object with an empty delegated field. I think that in this case Nil should be returned.

Add support for OSM data

It will be very efficient if we had a osm data importer within the gem. Right now I dont know if there's some implementation for doing so, if there's any please refer me that?

Not working with threads?

I am trying to get my application running on Rubinius & Puma web server. The combination runs my application in threads.

I keep getting this error whenever I start my application. (puma -p 3000)

undefined method '<<' on nil:NilClass. (NoMethodError)
mongoid_geospatial-2.7.0/lib/mongoid_geospatial/geospatial.rb:50

Any suggestions?

Point in Rails Form Builder

I use fields_for to create input element for Point.

= f.fields_for :location do |location|
  = location.text_field :x
  = location.text_field :y

This way can create point correctly, but it cannot load the correct values when edit a record. The result is same when I use "latitude" and "longitude" instead of "x" and "y". What way do you recommend? Thanks.

demongoize a missing point throws and error

New 2.2.0 release Point.rb#demongoize L26 when trying to demongoize a nil object will throw an error accessing the [0] (and [1]) elements of a nil object.

You commented out the return unless object && !object.empty? code. Perhaps just rescue with nil instead of returning if the object is empty as this is what was returned previously.

Thoughts?

Empty arrays persisted in database get demongoized and throw ArgumentError

I ended up having an empty array written to the database for my Point, and it becomes impossible to fix it from the console.

Mongoid-Geospatial will try to deserialize the empty array and instanciate the Point object from the array coordinates. It results an ArgumentError: wrong number of arguments (given 0, expected 2..3)

I am not sure how and if this should be handled by the gem

Issue with rgeo, to_geo and Line

Hi,

we have an issue with the following code

Mongoid::Geospatial.use_rgeo

class River
  include Mongoid::Document
  include Mongoid::Geospatial

  field :source, type: Line
end

river = River.new(source: [[5,5],[6,5],[6,6],[5,6]])

it results in

2.0.0p195 :036 > river.source
 => [[5, 5], [6, 5], [6, 6], [5, 6]] 
2.0.0p195 :037 > river.source.class
 => Mongoid::Geospatial::Line 
2.0.0p195 :038 > river.source.to_geo
 => nil 

we expect that to_geo returns a rgeo linestring, without having to do the following:

2.0.0p195 :039 > points = river.source.map{ |p| RGeo::Geographic.spherical_factory.point(*p) }
 => [#<RGeo::Geographic::SphericalPointImpl:0x3fca55ef84e0 "POINT (5.0 5.0)">, #<RGeo::Geographic::SphericalPointImpl:0x3fca55ef815c "POINT (6.0 5.0)">, #<RGeo::Geographic::SphericalPointImpl:0x3fca55f2fbe8 "POINT (6.0 6.0)">, #<RGeo::Geographic::SphericalPointImpl:0x3fca55f2f634 "POINT (5.0 6.0)">] 
2.0.0p195 :041 > line_string = RGeo::Geographic.simple_mercator_factory.line_string(points)
 => #<RGeo::Geographic::ProjectedLineStringImpl:0x3fca55f9bb2c "LINESTRING (5.0 5.0, 6.0 5.0, 6.0 6.0, 5.0 6.0)"> 

is this issue related to mongoid_geospatial or to rgeo?

Thanks

PS: Point.to_geo is ok and spherical_factory is the same of simple_mercator_factory

Nearby with range

Hello dear,

I need make this query below, but I need set the maxDistance por exemplo 1000 meters
Bar.nearby(my.location)

In MongoDB documentation

{
   <location field>: {
     $near: {
       $geometry: {
          type: "Point" ,
          coordinates: [ <longitude> , <latitude> ]
       },
       $maxDistance: <distance in meters>,
       $minDistance: <distance in meters>
     }
   }
}

thank you very munch

Make travis green

Mongoid 5 returns Float on Model#count , very weird.
Only on Travis.

Use LatLong instead of LongLat

So this is a mistake for this gem, the ISO 6709 defines that always Longitude must be before than Latitude, so please you should follow this convention in order to avoid problems with sync with clients

error: to_geo for Polygon

class District
include Mongoid::Document
include Mongoid::Geospatial
include Mongoid::Timestamps
field :area, type: Polygon
end

with georuby

district_instance.area.to_geo

gives

undefined method from_array' for GeoRuby::SimpleFeatures::Polygon:Class .../.rvm/gems/ruby-1.9.3-p194/bundler/gems/mongoid_geospatial-17af8420db58/lib/mongoid_geospatial/wrappers/georuby.rb:39:into_geo'

mongoid_geospatial/wrappers/georuby.rb:39
GeoRuby::SimpleFeatures::Polygon.from_array(self)
should be replaced by
GeoRuby::SimpleFeatures::Polygon.from_coordinates([self])

How can I get geo_near max_distance results ordered by distance?

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

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

I'm trying on mongoid_geospatial(which uses mongoid libraries) with no success and I could not find any resource except this one MongoDB Aggregate geoNear maxdistance but I don't know how to convert mongo that to mongoid.

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

The code in my Controller

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

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

The code in my model

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

Configuring with rgeo

$ Mongoid::Geospatial.with_rgeo!
#=> LoadError: cannot load such file -- mongoid_geospatial/ext/rgeo_spherical_point_impl

I get the the above error when I try to include with_rgeo! in initializer or rails conolse. I justed added gem 'mongoid-geospatial', github: 'nofxx/mongoid-geospatial' to Gemfile

Undefined method bson_type for Mongoid::Geospatial::Point : Aggregations

Hi,
This is the stuff I'm running :

Rails : 4.2.10
Mongoid Version : 5.0.2
Mongoid-Geospatial : 5.0.0

Document Setup:

class Workflow::Location
         embeds_many :tlocations
        field :location, type: Point
end

While performing a $geoNear aggregation as follows:

    response = Location.collection.aggregate([{
					"$geoNear" => {
						"near" => {
							"type" => "Point",
							"coordinates" => point
						},
						"spherical" => true,
						"query" => {
							"$and" => [
								{
									"tlocations" => {
									"booked" => false,
			 	    					"entity_category" => "1a",
			 	    					"start_time" => {
			 	    						"$gte" => time_range[0],
			 	    						"$lte" => time_range[1]
			 	    					}
									}
								},
								{
									"tlocations" => {
									"booked" => false,
			 	    					"entity_category" => "1",
			 	    					"start_time" => {
			 	    						"$gte" => time_range[0],
			 	    						"$lte" => time_range[1]
			 	    					}
									}	
								}
							]
						}
					}
	}])

When I call :

response.count

I get the error :

undefined method `bson_type' for #<Mongoid::Geospatial::Point:0x0055f2ca5a8ff8>

Any operation on the aggregation response, produces this error. It seems that it is unable to cast the "point" returned in the aggregation response to a Geospatial::Point object. Any help is appreciated, I am totally stuck with this for several hours now.

Bhargav

Require rgeo-geojson with rgeo for easier conversions and wider support?

As the title says, I propose that if an user wants to install this gem with rgeos support, they will also be required to install the rgeos-geojson package.

If we do that, then we can replace the whole rgeo.rb wrapper by calls to this library, which has more built-in robustness and a variety of functions already implemented.

And this will make it much easier to add support to MultiPoint, MultiLineString and MultiPolygon classes in the future, as they are already supported by that library.

Would this kind of change and additional optional dependency be ok?

Rake tests fail on MongoDB version 3.6.8

When running bundler exec rake I got two errors. Attached is the stdout of that command:
tests.txt (if you cat it, it will look nice with colors just as with rake)

When trying to get to the bottom of it, I found out that after MongoDB version 3.2, a new version of indexes is being used https://docs.mongodb.com/manual/core/2dsphere/ . I have MongoDB version 3.6, so that could be the cause, but apparently your travis tests are passing with a MongoDB version 3.2 so I'm not so sure

One possible fix would be to force the creation of Version 2 indexes. Or to just ignore the version number when doing the check on the tests. Or to check against which version to compare, according to the MongoDB version

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.