Oracle / PostgreSQL → MongoDB

Migrate Into MongoDB — as Real Documents

Everyone migrates to PostgreSQL. Going relational → MongoDB is the harder, under-served direction — and doing it right means real document modelling: typed values, indexes from your keys, and foreign keys folded into embedded arrays. Not tables dumped as flat collections.

1:1 + 1:N
Flat load or FK embedding
Decimal128
Exact numeric fidelity
100%
Document count-verified
0
External API calls

How It Works

01

Connect

Point DBMigrateAIPro at your Oracle or PostgreSQL source and your MongoDB target. It reads the full relational schema — tables, columns, types, primary keys, unique constraints, indexes and foreign keys — with no manual inventory.

02

Load as typed documents

Each table becomes a collection and each row a typed BSON document. Numbers stay numbers (NUMBER(p,s) → Decimal128, exact), dates become datetimes, booleans stay booleans, BLOBs become Binary, NULLs become null — no stringifying everything through CSV.

03

Build indexes + verify

Primary keys and unique constraints become unique MongoDB indexes; secondary indexes carry over. Every collection is then count-validated against the source so a rejected document (e.g. a >16MB BSON row) is surfaced, never silently dropped.

04

Embed related tables (optional)

Turn on 1:N embedding and DBMigrateAIPro folds leaf child tables into their parent as nested arrays — auto-detected from foreign keys. The idiomatic document shape, without hand-writing an aggregation pipeline.

Flat Collections vs Embedded Documents

A customers table and its orders can migrate as two disconnected collections — or as one document shaped for how MongoDB actually reads.

Flat: two collections (the naive copy)
// customers
{ "_id": 1, "name": "Ann" }

// orders  (separate collection)
{ "_id": 10, "customer_id": 1, "total": 50.00 }
{ "_id": 11, "customer_id": 1, "total": 70.00 }

// every read is a manual $lookup join
Embedded: one document (FK-driven)
// customers  (orders folded in as an array)
{
  "_id": 1,
  "name": "Ann",
  "orders": [
    { "_id": 10, "total": { "$numberDecimal": "50.00" } },
    { "_id": 11, "total": { "$numberDecimal": "70.00" } }
  ]
}

Auto-detected from the foreign key. Leaf child → embedded array · junction / referenced tables stay standalone · totals preserved as exact Decimal128.

What Gets Modelled

Structure

  • Table → collection
  • Row → typed BSON document
  • Primary key → unique index
  • Unique constraint → unique index
  • Secondary indexes → carried over
  • Foreign key (1:N) → embedded array (optional)

Type fidelity

  • NUMBER(p,s) → Decimal128 (exact — money never becomes a lossy float)
  • DATE / TIMESTAMP → BSON datetime
  • NUMBER / INTEGER → int / long
  • VARCHAR / CLOB / NCLOB → string
  • BLOB / RAW → BSON Binary
  • BOOLEAN → bool
  • NULL → null (not the string "null")

Common Gotchas

These are the issues that quietly wreck relational → document migrations. DBMigrateAIPro handles every one of them.

Tables ≠ collections

A naive migration copies each table to a collection and calls it done — that is SQL with extra steps, not a document model. DBMigrateAIPro can fold 1:N children into their parent as embedded arrays so the data is shaped the way MongoDB is meant to be queried.

Numbers as strings

Many tools route data through CSV and land every value as a string, corrupting money and dates. We derive a typed transport schema so NUMBER(p,s) arrives as exact Decimal128 and timestamps as real datetimes.

Junction / M:N tables

A join table with two foreign keys has no single owner, so embedding it into one parent would double-count. These are kept as standalone collections, with a logged reason — count integrity is preserved.

The 16MB document limit

A parent with a huge child set can exceed MongoDB’s 16MB BSON limit. The load is resilient: an oversized document is reported by count validation instead of crashing the run, so you see exactly what needs a different shape.

Dangling foreign keys

When a child row references a missing parent, embedding it would lose it. Instead the child collection is kept holding exactly the orphans — nothing is duplicated and nothing is silently dropped.

Hidden Oracle index columns

Function-based indexes are backed by hidden SYS_NC columns that are not real document fields. We skip them so you don’t get dead indexes on keys that don’t exist in the documents.

Prerequisites

  • A reachable MongoDB target (self-managed or Atlas); pymongo on the agent host
  • Source credentials for Oracle (thin-mode oracledb, no client install) or PostgreSQL
  • Network access from the DBMigrateAIPro agent to the MongoDB port (default 27017)
  • For embedding: foreign keys defined on the source (they drive the 1:N detection)

Model your data the document way

Read the deep-dive on turning foreign keys into embedded documents, or download the free desktop tool and run a proof-of-concept in under an hour.