nod*_*rog 6 ruby sql postgis ruby-on-rails
我想在构建用于带有activerecord-postgis-adapter的rails的sql查询时提供一些帮助.我一直在做相当多的阅读,但现在有点卡住了,任何帮助都会非常感激.
我有两个模型事件和领域:
事件具有"几何"列,其类型为Point
class Event < ActiveRecord::Base
self.rgeo_factory_generator = RGeo::Geos.factory_generator
end
t.spatial "geometry", :limit => {:srid=>4326, :type=>"polygon", :geographic=>true}
Run Code Online (Sandbox Code Playgroud)
区域有一个"几何"列,其类型为Polygon
class Area < ActiveRecord::Base
self.rgeo_factory_generator = RGeo::Geos.factory_generator
end
t.spatial "geometry", :limit => {:srid=>4326, :type=>"point", :geographic=>true}
Run Code Online (Sandbox Code Playgroud)
我可以在谷歌地图上创建和绘制事件和区域,并通过单击地图并保存到数据库来创建区域.
我希望能够执行以下2个查询:
我知道我可能会在这里问一点,但任何帮助都会非常感激
非常感谢
这是一个快速的方法来做到这一点.这些只会返回ActiveRecord对象的数组.
class Area
def events
Event.joins("INNER JOIN areas ON areas.id=#{id} AND st_contains(areas.geometry, events.geometry)").all
end
end
class Event
def areas
Area.joins("INNER JOIN events ON events.id=#{id} AND st_contains(areas.geometry, events.geometry)").all
end
end
Run Code Online (Sandbox Code Playgroud)
您可能应该记住(缓存结果),这样每次调用方法时都不会查询数据库.那应该是直截了当的; 我将它作为练习留给读者.
这可能是可能得到复杂,在一个真正的Rails协会代理包装这件事(这样你就可以得到所有的Rails协会好吃的东西).我没有看过这个.在任何情况下它都不是标准的Rails关联,因为你没有存储ID.
第十二是正确的:您应该为两个表创建空间索引.Activerecord-postgis-adapter应该可以在迁移中轻松完成.
change_table :events do |t|
t.index :geometry, :spatial => true
end
change_table :areas do |t|
t.index :geometry, :spatial => true
end
Run Code Online (Sandbox Code Playgroud)
如果您在安装postgis时遇到问题,我最近就这些内容写了一堆博客文章.查看http://www.daniel-azuma.com/blog/archives/category/tech/georails.我也是rgeo和activerecord-postgis-adapter本身的作者,所以如果你遇到困难我很乐意提供帮助.
这个答案对您来说将是一项正在进行的工作。我对 ruby on Rails 不太了解,但我应该能够帮助您完成数据库部分。
您有两个表,包含多边形的区域和将事件保存为单个点的事件(如果事件也是一个区域并且您试图挑选出重叠区域...如果事件是单个点,则情况会更复杂点这有效)。
Select *
from area a inner join event e on 1=1
Run Code Online (Sandbox Code Playgroud)
这将创建加入每个事件的每个区域的列表...如果您有 500 个事件和 20 个区域,则此查询将返回 10'000 行。现在您想要过滤此事件,以便仅过滤它们所加入的区域内的事件。我们可以使用 st_contains 作为 st_contains(polygon,point):
where st_contains(a.polygon,e.point) = 't'
Run Code Online (Sandbox Code Playgroud)
如果你运行这个,它应该给你一个。,e。对于区域内的所有活动。现在只要数你想数的就可以了。
select a.id, count(1)
from area a inner join event e on 1=1
where st_contains(a.polygon,e.point) = 't'
group by 1
Run Code Online (Sandbox Code Playgroud)
这将为您提供所有区域的列表(按 ID)以及其中的事件计数。用 e.id 替换 a.id 将给出事件 id 的列表以及它们所在的数字区域。
不幸的是,我不知道如何在 Ruby 中表达这些查询,但是您需要的数据库概念都在这里......
出于速度考虑,您应该查看 Postgres 的 GIStree 索引...索引多边形的性能呈指数级提高。
编辑:
PostGIS 是 Postgres 附带的一个 contrib 文件,但标准安装中不存在...您需要找到此 contrib 文件。这些将在您的数据库中安装一系列 GIS 功能,包括 ST_Contains。(函数驻留在数据库中,因此请确保将函数安装在您正在使用的数据库中)
PostGIS contrib 文件安装的第二件事是 template_postGIS 数据库,该数据库是几何数据类型所需的(在安装此数据库之前,geom 作为数据类型将不存在)。