TigerData logo
TigerData logo
  • Product

    Tiger Cloud

    Robust elastic cloud platform for startups and enterprises

    Agentic Postgres

    Postgres for Agents

    TimescaleDB

    Postgres for time-series, real-time analytics and events

  • Docs
  • Pricing

    Pricing

    Enterprise Tier

  • Developer Hub

    Changelog

    Benchmarks

    Blog

    Community

    Customer Stories

    Events

    Support

    Integrations

    Launch Hub

  • Company

    Contact us

    About

    Timescale

    Partners

    Security

    Careers

Log InTry for free
Home
Is Your Data Time Series? Data Types Supported by PostgreSQL and TimescaleUnderstanding Database Workloads: Variable, Bursty, and Uniform PatternsTime-Series Analysis and Forecasting With Python What Is Temporal Data?What Are Open-Source Time-Series Databases—Understanding Your OptionsAWS Time-Series Database: Understanding Your OptionsStationary Time-Series AnalysisThe Best Time-Series Databases ComparedAlternatives to TimescaleWhy Consider Using PostgreSQL for Time-Series Data?Time-Series Analysis in RWhat Is a Time Series and How Is It Used?How to Work With Time Series in Python?Tools for Working With Time-Series Analysis in PythonGuide to Time-Series Analysis in PythonUnderstanding Autoregressive Time-Series ModelingCreating a Fast Time-Series Graph With Postgres Materialized Views
Optimizing Your Database: A Deep Dive into PostgreSQL Data TypesHow to Install PostgreSQL on LinuxUnderstanding FROM in PostgreSQL (With Examples)How to Address ‘Error: Could Not Resize Shared Memory Segment’ Understanding FILTER in PostgreSQL (With Examples)How to Install PostgreSQL on MacOS5 Common Connection Errors in PostgreSQL and How to Solve ThemUnderstanding HAVING in PostgreSQL (With Examples)How to Fix No Partition of Relation Found for Row in Postgres DatabasesHow to Fix Transaction ID Wraparound ExhaustionUnderstanding LIMIT in PostgreSQL (With Examples)Understanding PostgreSQL FunctionsUnderstanding ORDER BY in PostgreSQL (With Examples)PostgreSQL Mathematical Functions: Enhancing Coding EfficiencyUnderstanding PostgreSQL WITHIN GROUPUnderstanding WINDOW in PostgreSQL (With Examples)Using PostgreSQL String Functions for Improved Data AnalysisPostgreSQL Joins : A SummaryUnderstanding PostgreSQL Conditional FunctionsStructured vs. Semi-Structured vs. Unstructured Data in PostgreSQLUnderstanding DISTINCT in PostgreSQL (With Examples)What Is a PostgreSQL Cross Join?Understanding percentile_cont() and percentile_disc() in PostgreSQLUnderstanding GROUP BY in PostgreSQL (With Examples)Data Processing With PostgreSQL Window FunctionsUnderstanding WHERE in PostgreSQL (With Examples)Data Partitioning: What It Is and Why It MattersUnderstanding PostgreSQL Array FunctionsUnderstanding ACID Compliance Understanding PostgreSQL's COALESCE FunctionUnderstanding the rank() and dense_rank() Functions in PostgreSQLUnderstanding PostgreSQLUnderstanding OFFSET in PostgreSQL (With Examples)Understanding PostgreSQL Date and Time FunctionsUnderstanding the Postgres string_agg FunctionWhat Is a PostgreSQL Full Outer Join?What Is a PostgreSQL Inner Join?What Is a PostgreSQL Left Join? And a Right Join?Strategies for Improving Postgres JOIN PerformancePostgreSQL Join Type TheoryA Guide to PostgreSQL ViewsUnderstanding Foreign Keys in PostgreSQLUnderstanding PostgreSQL User-Defined FunctionsUnderstanding SQL Aggregate FunctionsUsing PostgreSQL UPDATE With JOINWhat Is Data Compression and How Does It Work?What Is Data Transformation, and Why Is It Important?What Characters Are Allowed in PostgreSQL Strings?Understanding PostgreSQL SELECTSelf-Hosted or Cloud Database? A Countryside Reflection on Infrastructure ChoicesUnderstanding the Postgres extract() Function
How to Choose a Database: A Decision Framework for Modern ApplicationsHandling Large Objects in PostgresDetermining the Optimal Postgres Partition SizeNavigating Growing PostgreSQL Tables With Partitioning (and More)SQL/JSON Data Model and JSON in SQL: A PostgreSQL PerspectiveHow to Use PostgreSQL for Data TransformationPostgreSQL Performance Tuning: Designing and Implementing Your Database SchemaGuide to PostgreSQL PerformancePostgreSQL Performance Tuning: Key ParametersPostgreSQL Performance Tuning: Optimizing Database IndexesHow to Reduce Bloat in Large PostgreSQL TablesAn Intro to Data Modeling on PostgreSQLDesigning Your Database Schema: Wide vs. Narrow Postgres TablesGuide to PostgreSQL Database OperationsBest Practices for Time-Series Data Modeling: Single or Multiple Partitioned Table(s) a.k.a. Hypertables Explaining PostgreSQL EXPLAINWhat Is a PostgreSQL Temporary View?PostgreSQL Performance Tuning: How to Size Your DatabaseBest Practices for (Time-)Series Metadata Tables A PostgreSQL Database Replication GuideHow to Compute Standard Deviation With PostgreSQLA Guide to Data Analysis on PostgreSQLA Guide to Scaling PostgreSQLRecursive Query in SQL: What It Is, and How to Write OneHow to Query JSON Metadata in PostgreSQLHow to Query JSONB in PostgreSQLGuide to PostgreSQL SecurityOptimizing Array Queries With GIN Indexes in PostgreSQLPg_partman vs. Hypertables for Postgres PartitioningTop PostgreSQL Drivers for PythonUnderstanding PostgreSQL TablespacesWhat Is Audit Logging and How to Enable It in PostgreSQLWhen to Consider Postgres PartitioningGuide to Postgres Data ManagementHow to Index JSONB Columns in PostgreSQLHow to Monitor and Optimize PostgreSQL Index PerformanceA Guide to pg_restore (and pg_restore Example)How PostgreSQL Data Aggregation WorksHow to Use Psycopg2: The PostgreSQL Adapter for PythonBuilding a Scalable DatabaseGuide to PostgreSQL Database Design
Best Practices for Postgres Data ManagementHow to Store Video in PostgreSQL Using BYTEABest Practices for Postgres PerformanceHow to Design Your PostgreSQL Database: Two Schema ExamplesBest Practices for Scaling PostgreSQLHow to Handle High-Cardinality Data in PostgreSQLBest Practices for PostgreSQL AggregationBest Practices for Postgres Database ReplicationHow to Use a Common Table Expression (CTE) in SQLBest Practices for Postgres SecurityBest Practices for PostgreSQL Database OperationsBest Practices for PostgreSQL Data AnalysisTesting Postgres Ingest: INSERT vs. Batch INSERT vs. COPYHow to Manage Your Data With Data Retention PoliciesHow to Use PostgreSQL for Data Normalization
PostgreSQL Extensions: amcheckPostgreSQL Extensions: Unlocking Multidimensional Points With Cube PostgreSQL Extensions: hstorePostgreSQL Extensions: ltreePostgreSQL Extensions: Secure Your Time-Series Data With pgcryptoPostgreSQL Extensions: pg_prewarmPostgreSQL Extensions: pgRoutingPostgreSQL Extensions: pg_stat_statementsPostgreSQL Extensions: Database Testing With pgTAPPostgreSQL Extensions: Install pg_trgm for Data MatchingPostgreSQL Extensions: PL/pgSQLPostgreSQL Extensions: Using PostGIS and Timescale for Advanced Geospatial InsightsPostgreSQL Extensions: Turning PostgreSQL Into a Vector Database With pgvectorPostgreSQL Extensions: Intro to uuid-ossp
What Is ClickHouse and How Does It Compare to PostgreSQL and TimescaleDB for Time Series?Timescale vs. Amazon RDS PostgreSQL: Up to 350x Faster Queries, 44 % Faster Ingest, 95 % Storage Savings for Time-Series DataWhat We Learned From Benchmarking Amazon Aurora PostgreSQL ServerlessTimescaleDB vs. Amazon Timestream: 6,000x Higher Inserts, 5-175x Faster Queries, 150-220x CheaperHow to Store Time-Series Data in MongoDB and Why That’s a Bad IdeaPostgreSQL + TimescaleDB: 1,000x Faster Queries, 90 % Data Compression, and Much MoreEye or the Tiger: Benchmarking Cassandra vs. TimescaleDB for Time-Series Data
Moving Past Legacy Systems: Data Historian vs. Time-Series DatabaseHow Hopthru Powers Real-Time Transit Analytics From a 1 TB TableUnderstanding IoT (Internet of Things)A Beginner’s Guide to IIoT and Industry 4.0Storing IoT Data: 8 Reasons Why You Should Use PostgreSQLHow to Choose an IoT DatabaseHow to Simulate a Basic IoT Sensor Dataset on PostgreSQLFrom Ingest to Insights in Milliseconds: Everactive's Tech Transformation With TimescaleHow Ndustrial Is Providing Fast Real-Time Queries and Safely Storing Client Data With 97 % CompressionWhy You Should Use PostgreSQL for Industrial IoT Data Migrating a Low-Code IoT Platform Storing 20M Records/DayHow United Manufacturing Hub Is Introducing Open Source to ManufacturingBuilding IoT Pipelines for Faster Analytics With IoT CoreVisualizing IoT Data at Scale With Hopara and TimescaleDB
Building AI Agents with Persistent Memory: A Unified Database ApproachA Brief History of AI: How Did We Get Here, and What's Next?A Beginner’s Guide to Vector EmbeddingsPostgreSQL as a Vector Database: A Pgvector TutorialUsing Pgvector With PythonHow to Choose a Vector DatabaseVector Databases Are the Wrong AbstractionUnderstanding DiskANNA Guide to Cosine SimilarityStreaming DiskANN: How We Made PostgreSQL as Fast as Pinecone for Vector DataImplementing Cosine Similarity in PythonVector Database Basics: HNSWVector Database Options for AWSVector Store vs. Vector Database: Understanding the ConnectionPgvector vs. Pinecone: Vector Database Performance and Cost ComparisonHow to Build LLM Applications With Pgvector Vector Store in LangChainHow to Implement RAG With Amazon Bedrock and LangChainRetrieval-Augmented Generation With Claude Sonnet 3.5 and PgvectorRAG Is More Than Just Vector SearchImplementing Filtered Semantic Search Using Pgvector and JavaScriptWhen Should You Use Full-Text Search vs. Vector Search?HNSW vs. DiskANNPostgreSQL Hybrid Search Using Pgvector and CohereRefining Vector Search Queries With Time Filters in Pgvector: A TutorialUnderstanding Semantic SearchWhat Is Vector Search? Vector Search vs Semantic SearchText-to-SQL: A Developer’s Zero-to-Hero GuideNearest Neighbor Indexes: What Are IVFFlat Indexes in Pgvector and How Do They WorkBuilding an AI Image Gallery With OpenAI CLIP, Claude Sonnet 3.5, and Pgvector
How to Choose a Real-Time Analytics DatabaseData Analytics vs. Real-Time Analytics: How to Pick Your Database (and Why It Should Be PostgreSQL)Understanding OLTPOLAP Workloads on PostgreSQL: A GuideColumnar Databases vs. Row-Oriented Databases: Which to Choose?How to Choose an OLAP DatabasePostgreSQL as a Real-Time Analytics DatabaseWhat Is the Best Database for Real-Time AnalyticsHow to Build an IoT Pipeline for Real-Time Analytics in PostgreSQL
Alternatives to RDSWhy Is RDS so Expensive? Understanding RDS Pricing and CostsEstimating RDS CostsHow to Migrate From AWS RDS for PostgreSQL to TimescaleAmazon Aurora vs. RDS: Understanding the Difference
5 InfluxDB Alternatives for Your Time-Series Data8 Reasons to Choose Timescale as Your InfluxDB Alternative InfluxQL, Flux, and SQL: Which Query Language Is Best? (With Cheatsheet)What InfluxDB Got WrongTimescaleDB vs. InfluxDB: Purpose Built Differently for Time-Series Data
Is Postgres Partitioning Really That Hard? An Introduction To HypertablesComplete Guide: Migrating from MongoDB to Tiger Data (Step-by-Step)How to Migrate Your Data to Timescale (3 Ways)Postgres TOAST vs. Timescale CompressionBuilding Python Apps With PostgreSQL: A Developer's GuideData Visualization in PostgreSQL With Apache SupersetMore Time-Series Data Analysis, Fewer Lines of Code: Meet HyperfunctionsPostgreSQL Materialized Views and Where to Find Them5 Ways to Monitor Your PostgreSQL DatabaseTimescale Tips: Testing Your Chunk Size
Postgres cheat sheet
HomeTime series basicsPostgres basicsPostgres guidesPostgres best practicesPostgres extensionsBenchmarks
Sections

Compression

Postgres TOAST vs. Timescale Compression

Build your app

How to Migrate Your Data to Timescale (3 Ways)Building Python Apps With PostgreSQL: A Developer's GuideData Visualization in PostgreSQL With Apache Superset5 Ways to Monitor Your PostgreSQL Database

Hyperfunctions

More Time-Series Data Analysis, Fewer Lines of Code: Meet Hyperfunctions

Hypertables

Is Postgres Partitioning Really That Hard? An Introduction To HypertablesTimescale Tips: Testing Your Chunk Size

Continuous aggregates

PostgreSQL Materialized Views and Where to Find Them

Database migration

Complete Guide: Migrating from MongoDB to Tiger Data (Step-by-Step)
TigerData logo

Products

Time-series and Analytics AI and Vector Enterprise Plan Cloud Status Support Security Cloud Terms of Service

Learn

Documentation Blog Tutorials Changelog Success Stories Time-series Database

Company

Contact Us Careers About Brand Community Code Of Conduct Events

Subscribe to the Tiger Data Newsletter

By submitting, you acknowledge Tiger Data's Privacy Policy

2026 (c) Timescale, Inc., d/b/a Tiger Data. All rights reserved.

Privacy preferences
LegalPrivacySitemap

Published at Jan 14, 2026

Complete Guide: Migrating from MongoDB to Tiger Data (Step-by-Step)

MongoDB to Tiger Data Migration Thumbnail Compressed

Written by Jakkie Koekemoer

Many production systems run both MongoDB and PostgreSQL concurrently. The typical pattern: MongoDB handles flexible schema requirements and rapid development, while PostgreSQL manages relational data, complex queries, and analytics workloads. This dual-database architecture creates operational overhead; two systems to monitor, backup, scale, and maintain.

Tiger Data consolidates these workloads into a unified platform. The system provides JSONB support for schema flexibility (equivalent to MongoDB's document model), Hypertables for time-series data ingestion and queries, and full SQL capabilities for relational operations. This architecture eliminates the need to maintain separate database systems while preserving the functional capabilities of each.

This guide documents the complete migration process from MongoDB to Tiger Data.

Here is a glimpse of the key takeaways:

Key Takeaway

Details

Migration Time

8-16 hours for typical workloads

Primary Benefit

3-10x faster aggregations; unified SQL interface

Complexity

Medium (Schema design is the main effort)

Cost Impact

Eliminate dual-database operational overhead

Data Model

JSONB for flexible schemas, Hypertables for time-series, standard tables for relational data

Target Use Cases

Event logs, user profiles, sensor data, transactional records

Query Language

Standard SQL with JSON operators

The following sections detail stepwise process along with common pitfalls and how to avoid them.

When to Migrate from MongoDB to Tiger Data

Should you migrate from MongoDB to Tiger Data? Migrate if you're running MongoDB alongside PostgreSQL for analytics, experiencing slow aggregation queries (>2 seconds), managing time-series data with manual partitioning, or need complex JOIN operations across collections. MongoDB's $lookup (join operations) is typically slower than PostgreSQL's native joins, especially for complex multi-table joins used in analytical queries—benchmarks show PostgreSQL delivers 4-15x faster performance on OLTP workloads and complex aggregations when data is properly structured.

Stay with MongoDB if your workload consists primarily of simple document lookups with minimal cross-collection queries, your schema changes multiple times per week, your application benefits from MongoDB's native sharding and replica set tooling, or your team has deep MongoDB expertise and limited need for complex relational queries or SQL-based analytics.

Understanding the Architecture Difference

Feature

MongoDB

Tiger Data

Data Model

Document collections (BSON)

Relational tables + JSONB support

Partitioning

Manual sharding with shard keys

Automatic time-based chunking (Hypertables)

Aggregations

Aggregation pipeline

Standard SQL GROUP BY with query planner

Joins

$lookup operator (limited)

Native SQL JOINs with foreign keys

Time-Series

Time-series collections (block processing)

Hypertables with columnar compression

Compression

WiredTiger compression

Native columnar compression (90%+ reduction)

Foundation

MongoDB 8.2+ (December 2025)

PostgreSQL 18 + TimescaleDB 2.24.x

Key architectural advantage: Tiger Data is built 100% on PostgreSQL with the TimescaleDB extension, meaning you get full PostgreSQL features plus specialized time-series optimizations. When you create a Hypertable, Tiger Data automatically partitions data into time-based chunks (default: 7 days) and manages them transparently. Queries use standard SQL, and the query planner automatically scans only relevant chunks.

Step-by-Step Migration Process

1. Analyze your MongoDB schema and query patterns

Before migrating, document your current architecture:

  • Identify collections with time-series data (require Hypertables)

  • Map relationships between collections (candidates for foreign keys)

  • Analyze aggregation pipeline queries (convert to SQL GROUP BY)

  • Determine which fields are truly schemaless (use JSONB) vs structured

Prerequisites:

  • MongoDB 4.0+ (mongodump compatibility)

  • PostgreSQL 15, 16, or 17

  • Tiger Data (TimescaleDB 2.20.0+ extension)

  • Python 3.8+ with pymongo and psycopg2 libraries

2. Install and configure Tiger Data

-- On PostgreSQL 15, 16, or 17, install the TimescaleDB extension CREATE EXTENSION IF NOT EXISTS timescaledb;

-- Verify installation SELECT extversion FROM pg_extension WHERE extname = 'timescaledb'; -- Expected: 2.24.0 or later (December 2025)

3. Design Your PostgreSQL schema

For time-series data (IoT sensors, metrics, logs):

-- Create table, then convert to Hypertable CREATE TABLE sensor_readings ( time TIMESTAMPTZ NOT NULL, sensor_id TEXT NOT NULL, location TEXT NOT NULL, temperature NUMERIC(5,2), humidity NUMERIC(5,2) );

-- Convert to Hypertable (automatic partitioning by time) SELECT create_hypertable('sensor_readings', 'time');

-- Create indexes for query patterns CREATE INDEX idx_sensor_location ON sensor_readings (sensor_id, location, time DESC);

For flexible document data:

-- JSONB approach for rapid migration CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id TEXT NOT NULL UNIQUE, data JSONB NOT NULL, created_at TIMESTAMPTZ NOT NULL );

-- GIN index for JSONB queries CREATE INDEX idx_users_data ON users USING GIN (data);

For relational data (orders, customers):

-- Normalized relational schema CREATE TABLE users ( user_id TEXT PRIMARY KEY, email TEXT NOT NULL UNIQUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() );

CREATE TABLE orders ( order_id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(user_id) ON DELETE CASCADE, amount NUMERIC(10,2) NOT NULL, status TEXT NOT NULL, order_date TIMESTAMPTZ NOT NULL );

CREATE INDEX idx_orders_user_date ON orders(user_id, order_date DESC);

4. Export and transform MongoDB data

from pymongo import MongoClient import psycopg2 from psycopg2.extras import execute_batch import json import os

# MongoDB connection mongo_client = MongoClient('mongodb://localhost:27017/') mongo_db = mongo_client['production_db']

# Tiger Data connection pg_conn = psycopg2.connect( host='your-instance.tigerdata.cloud', database='production', user='postgres', password=os.getenv('TIGERDATA_PASSWORD') ) pg_cursor = pg_conn.cursor()

# Batch insert for time-series data batch_size = 1000 batch = [] total_inserted = 0

INSERT_QUERY = """ INSERT INTO sensor_readings (time, sensor_id, location, temperature, humidity) VALUES (%s, %s, %s, %s, %s) """

try: # Get total count for progress tracking total_docs = mongo_db['sensor_readings'].count_documents({}) print(f"Total documents to migrate: {total_docs}") for doc in mongo_db['sensor_readings'].find().batch_size(batch_size): # Handle missing fields with defaults batch.append(( doc.get('timestamp'), doc.get('sensorId'), doc.get('location'), doc.get('temperature'), doc.get('humidity') )) if len(batch) >= batch_size: execute_batch(pg_cursor, INSERT_QUERY, batch) pg_conn.commit() total_inserted += len(batch) print(f"Inserted {total_inserted}/{total_docs} records ({total_inserted/total_docs*100:.1f}%)") batch = [] # Insert remaining records if batch: execute_batch(pg_cursor, INSERT_QUERY, batch) pg_conn.commit() total_inserted += len(batch) print(f"Migration complete: {total_inserted} records inserted")

except Exception as e: print(f"Error during migration: {e}") pg_conn.rollback() raise

finally: pg_cursor.close() pg_conn.close() mongo_client.close()

5. Configure compression and retention

-- Enable compression on Hypertable ALTER TABLE sensor_readings SET ( timescaledb.compress, timescaledb.compress_segmentby = 'sensor_id', timescaledb.compress_orderby = 'time DESC' );

-- Automatic compression policy (compress data older than 7 days) SELECT add_compression_policy('sensor_readings', INTERVAL '7 days');

-- Data retention policy (drop data older than 1 year) SELECT add_retention_policy('sensor_readings', INTERVAL '1 year');

-- Verify compression status (run after compression has executed) SELECT chunk_schema, chunk_name, compression_status, pg_size_pretty(before_compression_total_bytes) AS before, pg_size_pretty(after_compression_total_bytes) AS after, ROUND(100 - (after_compression_total_bytes::numeric / before_compression_total_bytes * 100), 1) AS compression_ratio FROM chunk_compression_stats('sensor_readings');

6. Create continuous aggregates for dashboard queries

-- Pre-compute hourly averages CREATE MATERIALIZED VIEW sensor_hourly_avg WITH (timescaledb.continuous) AS SELECT time_bucket('1 hour', time) AS bucket, sensor_id, AVG(temperature) AS avg_temp, AVG(humidity) AS avg_humidity FROM sensor_readings GROUP BY bucket, sensor_id;

-- Add refresh policy (refresh every hour, materialized data from 2 hours ago to 1 hour ago) SELECT add_continuous_aggregate_policy('sensor_hourly_avg', start_offset => INTERVAL '2 hours', end_offset => INTERVAL '1 hour', schedule_interval => INTERVAL '1 hour' );

-- Verify real-time aggregates are enabled (default behavior in TimescaleDB 2.0+) SELECT view_name, materialized_only FROM timescaledb_information.continuous_aggregates WHERE view_name = 'sensor_hourly_avg'; -- Expected: materialized_only = false (real-time enabled)

-- Query continuous aggregate -- Combines pre-computed data with real-time data automatically SELECT * FROM sensor_hourly_avg WHERE bucket > NOW() - INTERVAL '24 hours' AND sensor_id = 'temp_sensor_01' ORDER BY bucket DESC;

7. Update application queries

MongoDB aggregation pipeline:

// MongoDB db.orders.aggregate([ { $match: { status: "completed" } }, { $group: { _id: "$category", totalSales: { $sum: "$amount" }, avgOrderValue: { $avg: "$amount" } } }, { $sort: { totalSales: -1 } } ])

Tiger Data SQL equivalent:

-- Tiger Data (significantly faster for complex multi-table aggregations) SELECT category, SUM(amount) as total_sales, AVG(amount) as avg_order_value, COUNT(*) as order_count FROM orders WHERE status = 'completed' GROUP BY category ORDER BY total_sales DESC;

JSONB queries:

-- Query nested JSONB fields SELECT * FROM users WHERE data->'profile'->>'name' = 'Alex Chen';

-- Query array elements SELECT * FROM users WHERE data->'tags' ? 'premium';

-- Extract specific fields SELECT user_id, data->>'email' as email, data->'profile'->>'name' as name FROM users;

8. Validate and monitor performance

-- Compare record counts SELECT COUNT(*) FROM sensor_readings;

-- Analyze query performance EXPLAIN ANALYZE SELECT time_bucket('1 hour', time) AS hour, AVG(temperature) as avg_temp FROM sensor_readings WHERE time > NOW() - INTERVAL '24 hours' AND location = 'warehouse_a' GROUP BY hour ORDER BY hour DESC;

-- Monitor compression effectiveness SELECT hypertable_name, total_chunks, number_compressed_chunks, pg_size_pretty(before_compression_total_bytes) as uncompressed, pg_size_pretty(after_compression_total_bytes) as compressed FROM hypertable_compression_stats('sensor_readings');

Query Performance Comparison

Query Type

MongoDB Performance

Tiger Data Performance

Improvement

Simple document fetch by ID

~1ms (optimal)

~1ms (comparable)

Equal

Time-series aggregation (1M rows)

2-5 seconds

300-500ms

4-10x faster

Complex JOIN across 3+ tables

Not supported (requires app-level joins)

100-300ms (native joins)

N/A

Full-text search

Text indexes required

GIN indexes + tsvector

Comparable

Geo-spatial queries

Supported via 2dsphere

PostGIS extension required

Depends on workload

Note: Performance varies by query complexity, data distribution, and indexing strategy. MongoDB 8.0 introduced block processing for time-series collections, improving aggregation performance by 200%, but PostgreSQL’s query optimizer remains superior for analytical workloads requiring multiple joins and complex aggregations.

Storage Optimization Results

Tiger Data’s columnar compression typically achieves 80-97% storage reduction for time-series data, with results depending on data characteristics and configuration.

Verified examples:

  • Industrial IoT: 64 GB daily → ~2 GB (97% reduction)

  • OpenStreetMap data: 607 MB → 45 MB (93% reduction)

  • Average savings: 5x compression ratio (80% reduction)

Best compression candidates: Repetitive sensor readings, sequential timestamps, low-cardinality fields (device types, status codes), numeric measurements with predictable ranges.

Lower compression: High-cardinality text (UUIDs, random strings), encrypted data, spatial coordinates, frequently updated records.

Configuration tip: Set compress_segmentby to match WHERE clause filters and compress_orderby to time-based columns. See compression best practices for detailed guidance.

Reality check: The 90%+ rates represent optimal scenarios. Production deployments typically see 60-85% compression for mixed workloads. Always test on representative data samples.

Common Pitfalls and Solutions

  1. Over-normalizing flexible data: Not all MongoDB documents need relational normalization. Use JSONB for genuinely variable schema fields.

  2. Incorrect compression settings: Match compress_segmentby to your WHERE clause patterns. Poor segmentation forces decompression of unnecessary data. See best practices for using compress_segmentby here.

  3. Missing indexes: Tiger Data relies on indexes for query performance. Create indexes on Hypertables before large data loads (or defer until after bulk insert).

  4. Ignoring continuous aggregate limitations: Continuous aggregates don’t support DISTINCT, ORDER BY within aggregates, or window functions. Use standard materialized views for complex queries.

  5. Not testing in staging: Schema design decisions are difficult to reverse. Test migration approaches with representative data before production deployment.

When Dual-Database Architecture Still Makes Sense

In some cases, you may not need to eliminate MongoDB entirely. Consider hybrid approaches:

  • MongoDB: Operational data with frequent schema changes, user profiles, content management

  • Tiger Data: Analytical queries, time-series data, reporting, dashboards

  • Sync strategy: Use change data capture (CDC) tools like Debezium to replicate MongoDB changes to Tiger Data for analytics

Conclusion

Migrating from MongoDB to Tiger Data consolidates infrastructure while delivering measurable performance improvements for time-series and analytical workloads. The migration process requires careful schema design and query translation, but the operational simplification—one database, one query language, one monitoring system—reduces long-term maintenance burden. Tiger Data’s PostgreSQL foundation provides mature ecosystem integration, while its time-series extensions (Hypertables, compression, continuous aggregates) match or exceed specialized time-series databases.

Ready to consolidate your database infrastructure? Eliminate dual-database complexity and reduce operational costs by 60-80%. Start your free Tiger Data migration—most teams complete their first production cutover within 2 weeks following structured approaches. Access step-by-step migration guides, schema design templates, and dedicated support at no cost during your trial.

FAQ About MongoDB to Tiger Data Migration

Q: How long does MongoDB to Tiger Data migration take?

A: Migration duration varies significantly based on schema complexity, data volume, transformation requirements, and infrastructure. Factors include: document structure complexity, number of collections, required schema normalization, indexing strategy, and network bandwidth. Plan for thorough testing in a staging environment before estimating production timelines.

Q: Can I migrate MongoDB to Tiger Data without downtime?

A: Yes, using a dual-write strategy. Write to both databases simultaneously, backfill historical data, validate consistency, switch read traffic to Tiger Data, then decommission MongoDB. This requires application code changes to handle dual writes and conflict resolution.

Q: How do I convert MongoDB documents to SQL tables?

A: Three approaches: (1) Store entire documents in JSONB columns for rapid migration, (2) Convert to Hypertables for time-series data with automatic partitioning, (3) Normalize into relational tables with foreign keys for analytical workloads. Choose based on query patterns and data relationships.

Q: Is Tiger Data faster than MongoDB for time-series data?

A: For analytical aggregations on time-series data, Tiger Data typically outperforms MongoDB by 4-15x due to columnar compression, automatic chunk exclusion, and SQL query optimization. MongoDB 8.0 improved time-series performance with block processing (200% faster aggregations), but PostgreSQL’s mature query planner excels at complex analytical queries. MongoDB may perform better for simple document retrieval and denormalized data access patterns.

Q: What’s the storage difference between MongoDB and Tiger Data?

A: Tiger Data’s columnar compression typically achieves 90-98% storage reduction compared to uncompressed PostgreSQL tables for time-series data. Real-world example: a 10TB MongoDB time-series collection often compresses to 1-2TB in Tiger Data while maintaining or improving query performance due to reduced I/O.


About the author: Jakkie Koekemoer is the Engineering Manager at Draft.dev. With more than 20 years of experience as a developer, data engineer, and manager, he's committed to solving real problems and bringing the best out of people. He lives in Cape Town, South Africa.

On this page