Skip to content

PostgreSQL Analytics

PostgreSQL serves as the time-series analytics database for social media and content performance metrics.

Overview

Container Details

PropertyValue
Containermediamagic-postgres
Port5432
VersionPostgreSQL 16
Databasemediamagic_analytics
Usermediamagic

Schema

social_metrics

Daily aggregated metrics per platform.

sql
CREATE TABLE social_metrics (
    id SERIAL PRIMARY KEY,
    metric_date DATE NOT NULL,
    platform VARCHAR(50) NOT NULL,
    impressions INTEGER DEFAULT 0,
    engagement INTEGER DEFAULT 0,
    reach INTEGER DEFAULT 0,
    followers INTEGER DEFAULT 0,
    posts_count INTEGER DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    UNIQUE(metric_date, platform)
);
ColumnTypeDescription
metric_dateDATEDate of metrics
platformVARCHAR(50)Platform name (x, facebook, etc.)
impressionsINTEGERTotal impressions
engagementINTEGERTotal engagement actions
reachINTEGERUnique accounts reached
followersINTEGERFollower count snapshot
posts_countINTEGERPosts made that day

post_performance

Individual post performance tracking.

sql
CREATE TABLE post_performance (
    id SERIAL PRIMARY KEY,
    post_id VARCHAR(100) NOT NULL,
    platform VARCHAR(50) NOT NULL,
    ayrshare_id VARCHAR(100),
    content TEXT,
    posted_at TIMESTAMP,
    likes INTEGER DEFAULT 0,
    comments INTEGER DEFAULT 0,
    shares INTEGER DEFAULT 0,
    impressions INTEGER DEFAULT 0,
    clicks INTEGER DEFAULT 0,
    engagement_rate DECIMAL(5,2),
    collected_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    UNIQUE(post_id, platform, collected_at)
);
ColumnTypeDescription
post_idVARCHAR(100)Platform's post ID
platformVARCHAR(50)Platform name
ayrshare_idVARCHAR(100)Ayrshare post ID
likesINTEGERLike/favorite count
commentsINTEGERComment count
sharesINTEGERShare/retweet count
impressionsINTEGERView count
engagement_rateDECIMALCalculated rate

platform_followers

Historical follower counts for trend analysis.

sql
CREATE TABLE platform_followers (
    id SERIAL PRIMARY KEY,
    date DATE NOT NULL,
    platform VARCHAR(50) NOT NULL,
    count INTEGER NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    UNIQUE(date, platform)
);
ColumnTypeDescription
dateDATESnapshot date
platformVARCHAR(50)Platform name
countINTEGERFollower count

content_metrics

Video and podcast performance metrics.

sql
CREATE TABLE content_metrics (
    id SERIAL PRIMARY KEY,
    content_id VARCHAR(100) NOT NULL,
    platform VARCHAR(50) NOT NULL,
    platform_content_id VARCHAR(100),
    views INTEGER DEFAULT 0,
    watch_hours DECIMAL(10,2) DEFAULT 0,
    likes INTEGER DEFAULT 0,
    comments INTEGER DEFAULT 0,
    shares INTEGER DEFAULT 0,
    downloads INTEGER DEFAULT 0,
    collected_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    UNIQUE(content_id, platform, collected_at)
);
ColumnTypeDescription
content_idVARCHAR(100)EspoCRM content ID
platformVARCHAR(50)Platform name
viewsINTEGERView/play count
watch_hoursDECIMALTotal watch time
downloadsINTEGERDownload count (podcasts)

Entity Relationship Diagram

Common Queries

Follower Trend (Last 30 Days)

sql
SELECT 
    date,
    platform,
    count
FROM platform_followers
WHERE date >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY date, platform;

Top Posts by Engagement

sql
SELECT 
    post_id,
    platform,
    content,
    likes + comments + shares as total_engagement,
    engagement_rate
FROM post_performance
WHERE collected_at >= CURRENT_DATE - INTERVAL '7 days'
ORDER BY total_engagement DESC
LIMIT 10;

Daily Platform Performance

sql
SELECT 
    metric_date,
    platform,
    impressions,
    engagement,
    ROUND(engagement::numeric / NULLIF(impressions, 0) * 100, 2) as engagement_rate
FROM social_metrics
WHERE metric_date >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY metric_date DESC, platform;

Content Performance Comparison

sql
SELECT 
    content_id,
    platform,
    SUM(views) as total_views,
    SUM(watch_hours) as total_watch_hours,
    SUM(likes) as total_likes
FROM content_metrics
GROUP BY content_id, platform
ORDER BY total_views DESC;

Data Collection Flow

Initialization

The schema is created on first run via postgres/init.sql:

sql
-- postgres/init.sql
CREATE DATABASE mediamagic_analytics;

\c mediamagic_analytics

-- Create tables (as shown above)
CREATE TABLE social_metrics (...);
CREATE TABLE post_performance (...);
CREATE TABLE platform_followers (...);
CREATE TABLE content_metrics (...);

-- Create indexes
CREATE INDEX idx_social_metrics_date ON social_metrics(metric_date);
CREATE INDEX idx_post_performance_platform ON post_performance(platform);
CREATE INDEX idx_followers_date ON platform_followers(date);

Seeding Test Data

bash
docker compose exec -T postgres psql -U mediamagic -d mediamagic_analytics < postgres/seed-data.sql

Backup & Restore

Backup

bash
docker compose exec postgres pg_dump -U mediamagic mediamagic_analytics > backup.sql

Restore

bash
docker compose exec -T postgres psql -U mediamagic mediamagic_analytics < backup.sql

Grafana Integration

PostgreSQL is configured as a data source in Grafana:

yaml
# grafana/provisioning/datasources/postgres.yml
datasources:
  - name: PostgreSQL
    type: postgres
    url: postgres:5432
    database: mediamagic_analytics
    user: mediamagic
    secureJsonData:
      password: ${POSTGRES_PASSWORD}

Performance Tips

Use Indexes

Add indexes on frequently filtered columns (date, platform).

Aggregate Old Data

Consider aggregating old granular data into daily/weekly summaries.

Partition by Date

For large datasets, consider partitioning tables by date.

MediaMagic CRM Documentation