Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example.env
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ DATABASE_HOST_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5
DATABASE_URL="${DATABASE_HOST_URL}/${POSTGRES_DB}?sslmode=disable"

GEOAPIFY_API_KEY=your_geoapify_key
PUBLIC_ROUTING_USER_ID=1

# Super token for trusted services. Send it as Authorization: Bearer ${API_TOKEN}.
#API_TOKEN=change-me
Expand Down
6 changes: 6 additions & 0 deletions migrations/000016_add_parking_zone_centroids.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DROP INDEX IF EXISTS idx_parking_zones_active_centroid_lat;
DROP INDEX IF EXISTS idx_parking_zones_active_centroid_lon;

ALTER TABLE parking_zones
DROP COLUMN IF EXISTS centroid_latitude,
DROP COLUMN IF EXISTS centroid_longitude;
57 changes: 57 additions & 0 deletions migrations/000016_add_parking_zone_centroids.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
ALTER TABLE parking_zones
ADD COLUMN IF NOT EXISTS centroid_latitude DOUBLE PRECISION,
ADD COLUMN IF NOT EXISTS centroid_longitude DOUBLE PRECISION;

-- Заполняем центроиды для уже существующих зон.
-- Берём среднее по точкам внешнего кольца GeoJSON Polygon.
WITH points AS (
SELECT
pz.parking_zone_id,
(point.value ->> 0)::DOUBLE PRECISION AS longitude,
(point.value ->> 1)::DOUBLE PRECISION AS latitude
FROM parking_zones pz
CROSS JOIN LATERAL jsonb_array_elements(
CASE
WHEN jsonb_typeof(pz.geometry) = 'object'
AND pz.geometry ->> 'type' = 'Polygon'
AND jsonb_typeof(pz.geometry -> 'coordinates') = 'array'
AND jsonb_array_length(pz.geometry -> 'coordinates') > 0
AND jsonb_typeof(pz.geometry -> 'coordinates' -> 0) = 'array'
THEN pz.geometry -> 'coordinates' -> 0
ELSE '[]'::jsonb
END
) AS point(value)
WHERE jsonb_typeof(point.value) = 'array'
AND jsonb_array_length(point.value) >= 2
AND (point.value ->> 0) ~ '^-?[0-9]+(\.[0-9]+)?$'
AND (point.value ->> 1) ~ '^-?[0-9]+(\.[0-9]+)?$'
),
centroids AS (
SELECT
parking_zone_id,
AVG(latitude) AS centroid_latitude,
AVG(longitude) AS centroid_longitude
FROM points
WHERE latitude BETWEEN -90 AND 90
AND longitude BETWEEN -180 AND 180
GROUP BY parking_zone_id
)
UPDATE parking_zones pz
SET
centroid_latitude = c.centroid_latitude,
centroid_longitude = c.centroid_longitude
FROM centroids c
WHERE pz.parking_zone_id = c.parking_zone_id;

-- Индексы для быстрого радиусного поиска через bounding box.
CREATE INDEX IF NOT EXISTS idx_parking_zones_active_centroid_lat
ON parking_zones (centroid_latitude)
WHERE is_active = TRUE
AND centroid_latitude IS NOT NULL
AND centroid_longitude IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_parking_zones_active_centroid_lon
ON parking_zones (centroid_longitude)
WHERE is_active = TRUE
AND centroid_latitude IS NOT NULL
AND centroid_longitude IS NOT NULL;
57 changes: 57 additions & 0 deletions migrations/up/000016_add_parking_zone_centroids.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
ALTER TABLE parking_zones
ADD COLUMN IF NOT EXISTS centroid_latitude DOUBLE PRECISION,
ADD COLUMN IF NOT EXISTS centroid_longitude DOUBLE PRECISION;

-- Заполняем центроиды для уже существующих зон.
-- Берём среднее по точкам внешнего кольца GeoJSON Polygon.
WITH points AS (
SELECT
pz.parking_zone_id,
(point.value ->> 0)::DOUBLE PRECISION AS longitude,
(point.value ->> 1)::DOUBLE PRECISION AS latitude
FROM parking_zones pz
CROSS JOIN LATERAL jsonb_array_elements(
CASE
WHEN jsonb_typeof(pz.geometry) = 'object'
AND pz.geometry ->> 'type' = 'Polygon'
AND jsonb_typeof(pz.geometry -> 'coordinates') = 'array'
AND jsonb_array_length(pz.geometry -> 'coordinates') > 0
AND jsonb_typeof(pz.geometry -> 'coordinates' -> 0) = 'array'
THEN pz.geometry -> 'coordinates' -> 0
ELSE '[]'::jsonb
END
) AS point(value)
WHERE jsonb_typeof(point.value) = 'array'
AND jsonb_array_length(point.value) >= 2
AND (point.value ->> 0) ~ '^-?[0-9]+(\.[0-9]+)?$'
AND (point.value ->> 1) ~ '^-?[0-9]+(\.[0-9]+)?$'
),
centroids AS (
SELECT
parking_zone_id,
AVG(latitude) AS centroid_latitude,
AVG(longitude) AS centroid_longitude
FROM points
WHERE latitude BETWEEN -90 AND 90
AND longitude BETWEEN -180 AND 180
GROUP BY parking_zone_id
)
UPDATE parking_zones pz
SET
centroid_latitude = c.centroid_latitude,
centroid_longitude = c.centroid_longitude
FROM centroids c
WHERE pz.parking_zone_id = c.parking_zone_id;

-- Индексы для быстрого радиусного поиска через bounding box.
CREATE INDEX IF NOT EXISTS idx_parking_zones_active_centroid_lat
ON parking_zones (centroid_latitude)
WHERE is_active = TRUE
AND centroid_latitude IS NOT NULL
AND centroid_longitude IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_parking_zones_active_centroid_lon
ON parking_zones (centroid_longitude)
WHERE is_active = TRUE
AND centroid_latitude IS NOT NULL
AND centroid_longitude IS NOT NULL;
2 changes: 2 additions & 0 deletions src/db_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ class ParkingZone(Base):
pay = Column(Integer, nullable=False, default=0)
geometry = Column(JSONB, nullable=False)
image_polygon = Column(JSONB, nullable=False)
centroid_latitude = Column(Double, nullable=True)
centroid_longitude = Column(Double, nullable=True)
partner_id = Column(Integer, ForeignKey("partners.partner_id", ondelete="SET NULL"), nullable=True)
created_by_user_id = Column(Integer, ForeignKey("users.user_id", ondelete="SET NULL"), nullable=True)
is_active = Column(Boolean, default=True)
Expand Down
Loading
Loading