mongoid / mongoid-geospatial

A MongoDB/Mongoid Extension with optional GeoRuby/RGeo support.
http://rubygems.org/gems/mongoid-geospatial
MIT License
80 stars 31 forks source link

Problem when try to return a Polygon from database #46

Open mrmarcondes opened 8 years ago

mrmarcondes commented 8 years ago

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.

nofxx commented 8 years ago

Alou quase xará! 'Marcos' aqui... Vou testar essa parada! O new seria Polygon.new() Tenta spatial: true invés de sphere tb... sphre acho q é só pra ponto no mongo, ñ?

Tva vendo o findshop teu, manero! Se tu quiser ligar por cidades da uma olhada na gem geopolitical... Dá pra popular com todas as cidades/estados e por drop nos forms. Bom tb pra procura depois.

mrmarcondes commented 8 years ago

Olá @nofxx, obrigado pelo seu email!

Legal saber que brasileiro toca essa gem. Parabéns!

Ontem eu fiz um fork, e mudando o demongoize acabou quebrando alguns testes, mas para minha necessidade não tem problemas.

Vou alterar para spatial. Havia tentado inicialmente assim, mas por algum motivo que não me lembro agora, mudei para sphere.

Quanto ao findshop, é uma idéia antiga, que não estou mais mexendo, mas obrigado pela dica.

Vi seu repo e tem bastante coisa interessante. Depois vou dar uma fuçada.

Se puder contribuir com alguma coisa ai, por favor, avise-me, ok?

Abraços e obrigado, Marco(s)

nofxx commented 8 years ago

Alou Marco,

Cara, fui ver os docs, agora ñ entendi se mudou ou se sempre teve errado,,. Eu nao to convertendo pra geojson, achei q passar point, polygon era no index... Mais: ponto funcionando normal soh array: [x,y] inves de {type: Point, coordinates: [x,y]}

E agora José? hehe, amanhã vejo com calma. Sono... Souber mais avisa, abraço.

dblock commented 7 years ago

Just cleaning up old issues. What should we do with this?

nofxx commented 7 years ago

I need to review this, did mongodb changed or the implementation was never correct?

mongoize should do A or B?

Point(x,y)      ->  [x,y] or { type: Point, coordinates: [x,y] }
Polygon([[..]]) ->  [[]] or  {type: Polygon, coordinates: [[]] }
... so on
tedma4 commented 7 years ago

Having the same issue with a different error, because type was saved before coordinates in the hash. Reverse the order in the hash and you get the error from above Same setup

class Area
  include Mongoid::Document
  include Mongoid::Timestamps
  include Mongoid::Geospatial
  field :area_profile, type: Polygon, sphere: true
end

creating an area

> hash = {type: "Polygon", coordinates:  [[[0, 0], [3, 6], [6, 1], [0, 0]]]}
> area = Area.new(area_profile: hash)
> area.save # => true
> area.area_profile
TypeError: no implicit conversion of Hash into Integer
from /Users/tedmartinez/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/mongoid-geospatial-5.0.0/lib/mongoid/geospatial/geometry_field.rb:86:in `initialize'

removing && new(obj) fixes the problem

> Area.last.area_profile
    {"type"=>"Polygon", "coordinates"=>[[[0, 0], [3, 6], [6, 1], [0, 0]]]}
nofxx commented 7 years ago

@tedma4 you should never have to write the full hash:

> hash = {type: "Polygon", coordinates:  [[[0, 0], [3, 6], [6, 1], [0, 0]]]}
> area = Area.new(area_profile: hash)

Should be:
> area = Area.new(area_profile: [[[0, 0], [3, 6], [6, 1], [0, 0]]])

To my understanding, the polygon is only a index thing, field should be Array, not Hash. I need to confirm this with mongodb. (And if so if geospatial is generating the index correctly) If mongodb expects the Hash, need some code changing...so you aways just work with the Array.

ramonmacias commented 6 years ago

@nofxx Why are you using three level of arrays? why not use this instead:

area = Area.new(area_profile: [[0, 0], [3, 6], [6, 1], [0, 0]])

for me works fine if I use one array and inside arrays with coordinates

The thing here is if I use two level of array the Polygon methods works fine for example area.area_profile.center works well, but if I use three level of arrays this throws the exception TypeError: no implicit conversion of Hash into Integer.

But if we use two level of arrays then if I try to query something using polygons this throws Mongo::Error::OperationFailure: GeoJSON coordinates must be an array (2) for example using :loc.within_polygon