Core Mental Model & Data Modeling

A rough mapping:

PostgreSQL MongoDB Important difference
Table Collection Collection does not require every record to have identical fields
Row Document Document can contain nested objects and arrays
Column Field Fields may differ between documents
Primary key _id Every normal document has one; uniquely indexed by default
JSONB BSON document MongoDB's entire primary data model is document-oriented

In PostgreSQL, you normally start by thinking:

What are my entities and relationships? How should I normalize them?

In MongoDB, you more often start with:

What data does the application usually read and modify together?

Imagine an asset-heavy product:

BSON

MongoDB stores documents as BSON, not plain JSON. BSON supports nested documents/arrays and database-oriented types such as ObjectId, Date, int64, Decimal128, and binary data.

type Product struct {
	ID     primitive.ObjectID `bson:"_id,omitempty"`
	SKU    string             `bson:"sku"`
	Name   string             `bson:"name"`
	Assets []Asset            `bson:"assets"`
}
{
    "_id": ObjectId("..."),
    "sku": "TSHIRT-001",
    "name": "Black T-Shirt",

    "assets": [
        {
            "asset_id": "asset-101",
            "position": 1,
            "status": "ready",
            "variants": {
                "thumbnail": {
                    "width": 200,
                    "height": 200,
                    "s3_key": "products/101/thumb.webp"
                },
                "large": {
                    "width": 1600,
                    "height": 1600,
                    "s3_key": "products/101/large.webp"
                }
            }
        }
    ]
}

_id

Every document in a normal MongoDB collection has an _id that uniquely identifies it. If you don't provide one, drivers normally generate an ObjectId.

Flexible schema ≠ no schema

MongoDB has a flexible document schema rather than an absence of schema.

Without discipline, flexibility can actually create bugs:

{ "status": "ready" }
{ "status": 1 }
{ "processing_status": "READY" }

Document ≈ Aggregate

If these things are normally: