Skip to content
Go back

Using PostGIS for Location-Based Features in PostgreSQL

Using PostGIS for Location-Based Features in PostgreSQL

Introduction

PostGIS extends PostgreSQL with geospatial capabilities for storing and querying geographic data. This guide covers spatial data types, indexing, and location queries.

Prerequisites

Step 1: Enable PostGIS Extension

CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;

Step 2: Create Spatial Tables

CREATE TABLE locations (
  id SERIAL PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  geom GEOMETRY(Point, 4326) NOT NULL -- WGS84 coordinate system
);

-- Create spatial index for performance
CREATE INDEX idx_locations_geom ON locations USING GIST (geom);

Step 3: Insert Location Data

INSERT INTO locations (name, geom) VALUES
('New York City', ST_SetSRID(ST_MakePoint(-74.006, 40.7128), 4326)),
('Los Angeles', ST_SetSRID(ST_MakePoint(-118.2437, 34.0522), 4326)),
('Chicago', ST_SetSRID(ST_MakePoint(-87.6298, 41.8781), 4326));

Step 4: Proximity Queries

Find locations within 1000 km of a point:

SELECT name, ST_Distance(
  geom::geography,
  ST_SetSRID(ST_MakePoint(-74.006, 40.7128), 4326)::geography
) / 1000 AS distance_km
FROM locations
WHERE ST_DWithin(
  geom::geography,
  ST_SetSRID(ST_MakePoint(-74.006, 40.7128), 4326)::geography,
  1000000 -- 1000 km in meters
)
ORDER BY distance_km;

Step 5: Node.js Integration

npm install pg @types/pg
import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

export async function findNearbyLocations(
  longitude: number,
  latitude: number,
  radiusKm: number = 10
) {
  const query = `
    SELECT id, name, 
           ST_Distance(geom::geography, ST_SetSRID(ST_MakePoint($1, $2), 4326)::geography) / 1000 AS distance_km
    FROM locations
    WHERE ST_DWithin(
      geom::geography,
      ST_SetSRID(ST_MakePoint($1, $2), 4326)::geography,
      $3 * 1000
    )
    ORDER BY distance_km
  `;
  
  const result = await pool.query(query, [longitude, latitude, radiusKm]);
  return result.rows;
}

export async function createLocation(name: string, longitude: number, latitude: number) {
  const query = `
    INSERT INTO locations (name, geom)
    VALUES ($1, ST_SetSRID(ST_MakePoint($2, $3), 4326))
    RETURNING id, name
  `;
  
  const result = await pool.query(query, [name, longitude, latitude]);
  return result.rows[0];
}

Step 6: Advanced Spatial Queries

Area calculations and polygon queries:

-- Create polygon table
CREATE TABLE zones (
  id SERIAL PRIMARY KEY,
  name VARCHAR(255),
  boundary GEOMETRY(Polygon, 4326)
);

-- Insert a rectangular zone
INSERT INTO zones (name, boundary) VALUES (
  'Downtown Area',
  ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(
    -74.02 40.70, -73.99 40.70, -73.99 40.72, -74.02 40.72, -74.02 40.70
  )')), 4326)
);

-- Find points within polygon
SELECT l.name
FROM locations l
JOIN zones z ON ST_Within(l.geom, z.boundary)
WHERE z.name = 'Downtown Area';

Summary

PostGIS enables powerful location-based features in PostgreSQL with spatial indexing, proximity searches, and geometric operations for building location-aware applications.


Share this post on:

Previous Post
Implementing Multi-Tenant Database Schemas in PostgreSQL
Next Post
Building AI-Powered Search UI with Vector Embeddings