我有一个GeoDjango数据库表,如下所示:
# \d spirits_spirit
Table "public.myapp_mymodel"
Column | Type | Modifiers
----------+-----------------------+------------------
id | integer | not null default nextval('spirits_spirit_id_seq'::regclass)
activity | integer | not null
location | geography(Point,4326) |
当然还有更多的列,但这些是唯一可能相关的列。我还应该指出,这个表有可能非常大,在数十万甚至数百万行的范围内。
现在,我想要做的是改变匹配activity = 3
或其他任何对象的位置。该位置需要距离当前位置n
米,其中n
是一个介于10和100之间的随机数。
实际上,我希望我的对象移动,我想在单个UPDATE
查询中执行此操作,而不是在Python中循环所有内容...除非有人认为这样做是一个坏主意。
对我来说问题是我不知道该怎么做:
UPDATE
myapp_mymodel
SET
location.x = location + 0.5,
location.y = location + 0.2
WHERE
activity = 3;
...或者没有循环遍历所有内容,创建对象的实例,在Python中进行调整然后执行.save()
。我对PostGIS如何工作的把握目前仅限于GeoDjango如何通过它的ORM隐藏所有东西,所以我在这里问:
这可能吗?这甚至是个好主意吗?在Python循环中实现这一切真的更好吗?
答案 0 :(得分:1)
在我看来,最好在数据库级别进行数据更新,而不是将其带到客户端 - 这是数据库优化的事情之一。我不确定你是如何定义移动x和y的随机量,但你可以使用的一件事是ST_Translate,它会在x和y方向上移动一个几何体。所以在你的情况下,例如,
UPDATE
myapp_mymodel
SET
location = ST_Transform(ST_Translate(ST_Transform(location::geometry,
3857), random()*10, random()*10) ,4326)
WHERE
activity = 3;
其中x和y在0到10之间移动一些数字,并且几何体就地更新。这看起来比它更混乱。基本上,有四个步骤。
<强>买者即可。球形墨卡托(3857)由谷歌开发,以投影仪表覆盖全球。它使投影的数学非常容易处理(因为它假设为球形地球),但确实受到尺度/距离扭曲的影响,你从赤道得到的距离越远。如果您想要以米为单位进行极其精确的移动,则需要使用不同的坐标系。
注意:EPSG代表欧洲石油调查组,是管理空间参考系统的组织,例如4326或3857.这些在Postgis中称为SRID,空间参考ID。
注2 。您也可以使用度数的ST_Translate,但是您在x和y方向上的移动需要以度为单位表示。这将避免双重ST_Transform,但意味着添加另一个计算以将米转换为度数。
我已经在Postgres / Postgis上对数百万行进行了这种性质的更新而没有任何问题。唯一需要注意的是,您有足够的空间来存储更改,因为更新是单个事务,如果出现问题则需要回滚。根据活动字段中的值范围,在获取活动索引时可能也值得(解释是你的朋友)。