Architettura di dati e sistemi, dalle fondamenta Lezione 19 / 80

Document store: MongoDB e l'ascesa, la caduta e la rinascita

Quando i dati annidati sono il modello, cosa costa lo schema-on-read, e le lezioni operative che MongoDB ha insegnato all'industria.

Le due lezioni precedenti hanno coperto il modello relazionale (lezione 17) e il modello key-value (lezione 18). Questa copre la terza grande famiglia: i document store, dove ogni record è un albero a forma di JSON e lo schema è, almeno nominalmente, opzionale. Il prodotto canonico è MongoDB. La storia di MongoDB è un arco utile, perché ripercorre, in tempo reale, il ciclo dell’hype per la nuova tecnologia, della dolorosa realtà operativa, e poi della maturazione costante in uno strumento legittimo. Leggere quell’arco è il modo più veloce per capire sia per cosa vanno bene i document store sia dove il discorso intorno ad essi è andato fuori strada.

Il modello dei dati

Un document store tratta ogni record come un documento autocontenuto, di solito JSON o una variante binaria di JSON (BSON nel caso di MongoDB). Un documento è un albero di campi nominati i cui valori possono essere primitivi (stringhe, numeri, booleani, null, date), array, o documenti annidati. I documenti vivono dentro le collection, l’equivalente document-store delle tabelle. Non esiste uno schema fisso dichiarato a livello di collection; due documenti nella stessa collection possono avere campi diversi, tipi diversi per lo stesso nome di campo, o forme arbitrariamente diverse.

Un documento tipico potrebbe assomigliare a questo, concettualmente:

{
  "_id": "post_42",
  "title": "Hello world",
  "author": { "id": "user_7", "name": "Narcis" },
  "tags": ["intro", "meta"],
  "comments": [
    { "by": "user_3", "text": "nice", "at": "2026-04-12T10:30:00Z" },
    { "by": "user_5", "text": "+1",  "at": "2026-04-12T11:02:00Z" }
  ],
  "published_at": "2026-04-12T09:00:00Z"
}

L’intero post-con-commenti-e-autore vive in un singolo documento. Una read recupera tutto in un colpo solo. Una write aggiorna i campi al suo interno, possibilmente in modo atomico. La promessa era: questo è più vicino a come l’applicazione pensa ai dati, quindi l’impedance mismatch fra il database e il modello a oggetti scompare.

Rispetto all’equivalente relazionale, dove avresti una tabella posts, una tabella users, una tabella comments, e una tabella tags, il modello a documenti collassa quelle che sarebbero state tre o quattro join in una singola fetch di documento. Per il pattern di accesso “mostrami un post con tutto attaccato”, questa è una vittoria reale.

La promessa, intorno al 2010

MongoDB è uscito nel 2009. Il discorso dal 2010 al 2013 è stato implacabilmente entusiasta e il marketing era specifico: “i database schemaless sono più facili”; “JSON in, JSON out, niente da migrare”; “i team agili spediscono più in fretta senza l’attrito delle definizioni di schema.” La promessa ha venduto milioni di deployment di MongoDB, in molti casi a team che non avevano davvero bisogno del modello a documenti.

La mossa intellettuale sotto era reale anche se l’esecuzione era esagerata. Gli schemi SQL nel mondo Rails-and-Django dei primi anni 2010 erano davvero dolorosi: ogni nuova feature significava una migration, ogni migration significava una coreografia di deploy, gli ORM coprivano l’impedance mismatch e introducevano i loro bug. “Memorizza e basta il JSON” sembrava liberatorio. Per la fase prototipale di una startup, dove il prodotto cambia ogni settimana e nessuno conosce lo schema giusto, la promessa no-schema era attraente.

La promessa aveva due specifici punti ciechi. Primo, l’assenza di uno schema dichiarato non significa l’assenza di uno schema. Lo schema è implicito, sparso nel codice applicativo, e non imposto da alcun singolo componente. Due servizi scrivono nella stessa collection con forme sottilmente diverse. Un campo viene rinominato in un posto ma non in un altro. Una read in un terzo servizio crasha su un tipo inatteso. Lo schema esiste; semplicemente non è dove puoi vederlo.

Secondo, “più facile da evolvere” era una mezza verità. Sì, puoi cambiare la forma senza una migration. Ma i vecchi documenti, scritti sotto la vecchia forma, sono ancora nel database. Il codice applicativo deve gestire ogni forma storica per sempre, oppure scrivi una migration comunque, ma adesso senza l’aiuto del database.

La realtà, dal 2015 al 2020 circa

Il successivo mezzo decennio è stato un’educazione brutale per il mondo dei document store, e MongoDB ne ha preso la maggior parte. Due categorie di dolore.

Il dolore di correttezza è arrivato per primo. I default iniziali di MongoDB erano, a essere generosi, insicuri: le write tornavano successo prima di essere persistite in modo durevole, le replica potevano restare indietro senza warning, le garanzie di isolation erano più deboli di quanto gli utenti supponevano. I test Jepsen di Kyle Kingsbury fra il 2013 e il 2020 hanno trovato una sequenza di problemi: lost update sotto network partition, stale read dai secondari, transazioni che non si comportavano in modo davvero transazionale. MongoDB Inc. ha risposto, ha sistemato i problemi, e ha spedito default migliori, ma il danno reputazionale ha richiesto anni per essere riparato. “MongoDB is web scale” ha circolato nella community ingegneristica per gran parte degli anni 2010, pronunciato con una smorfia.

Il dolore operativo è arrivato in parallelo. Lo sharding ha funzionato male in pratica per anni. Le operazioni di cluster (rebalancing, backup, point-in-time recovery, schema change) erano o più difficili di quanto promesso o non realmente presenti. I team che sceglievano MongoDB sulla forza della promessa di developer experience scoprivano, sei mesi dopo, di operare un sistema distribuito senza la maturità operativa che Postgres aveva costruito in decenni.

Il risultato è stato una ritirata lenta e pubblica. La narrativa “document store come database primario” si è affievolita, e nel 2018 il consenso dell’industria era: usa i document store solo per casi specifici dove la forma è davvero quella giusta.

La rinascita, dal 2020 a oggi

Se hai smesso di leggere la storia di MongoDB nel 2018 ti saresti perso il rimbalzo. Lungo la seconda metà del decennio, MongoDB Inc. ha fatto il lavoro poco glamour di sistemare i problemi reali, e nel 2026 il prodotto è significativamente diverso da quello che Jepsen testava nel 2013.

Le transazioni multi-documento sono arrivate in MongoDB 4.0 (2018) con ACID propria all’interno di un replica set, e poi sono state estese ai cluster shardati nella 4.2. La difesa “i documenti sono atomici quindi non ti servono le transazioni” è stata mandata in pensione. Le write e read concern sono state strette: la write concern di default è ora majority, quindi una write viene confermata solo dopo che una maggioranza del replica set la possiede. È stata aggiunta la schema validation: puoi dichiarare un validator JSON Schema su una collection, e il database lo impone. La promessa “schemaless” è stata silenziosamente sostituita con “schema-flexible”, che è la versione onesta. Le aggregation pipeline sono maturate in un linguaggio di query serio con $lookup join, window function, e faceted search. Le operazioni di cluster sono migliorate su tutta la linea.

I report Jepsen degli anni 2020 raccontano una storia diversa rispetto a quelli degli anni 2010. Il prodotto passa test che era solito fallire. Le transazioni multi-documento funzionano come pubblicizzato, con la riserva che le transazioni a lunga durata su un cluster shardato hanno costi reali di performance. Il prodotto è ora una scelta legittima per i casi in cui il modello a documenti calza, e il discorso è, finalmente, calibrato.

Quando i document store calzano davvero

Esiste un piccolo insieme ben definito di workload dove il modello a documenti è lo strumento giusto. Ogni entità è un albero autocontenuto: un blog post con commenti e tag annidati, un prodotto con varianti e immagini annidate, un documento di configurazione, un ordine completo con line item e spedizione. Il pattern di accesso è “recupera tutta la cosa, modificane una parte, salvala di nuovo”, e la decomposizione relazionale dividerebbe questo su quattro o cinque tabelle senza chiari benefici al momento della read. Non hai bisogno spesso di transazioni cross-entity: il confine di atomicità in un document store è, di default, il documento, quindi le transazioni single-document sono gratis; se le tue transazioni di routine attraversano molti documenti, il modello a documenti non ti sta facendo risparmiare nulla. Schema evolution mentre un prodotto matura: i prodotti in fase iniziale beneficiano dell’aggiunta di campi sparsi senza una migration, anche se Postgres con JSONB può gestire pure questo. Documenti eterogenei nella stessa collection: prodotti diversi con attributi diversi, eventi diversi con payload diversi, dove le colonne fisse sono scomode e i campi opzionali sono naturali.

Se il tuo workload ha uno o due di questi tratti, un document store è una scelta ragionevole. Se non ne ha nessuno, stai pagando il costo di uno strumento poco familiare per benefici che non stai usando.

Quando SQL con JSONB è una scelta migliore

Postgres ha un tipo colonna JSON dal 2012, e JSONB (binario, indicizzato, query-friendly) dal 2014. Nel 2026 il feature set è maturo: indici GIN per lookup arbitrari su chiavi interne, indici di espressione per percorsi specifici, un ricco set di operatori, supporto JSONPath, buona integrazione con il query planner. La combinazione di uno schema relazionale per la parte strutturata più colonne JSONB per la parte flessibile copre la maggior parte degli use case per cui il modello a documenti veniva venduto, senza rinunciare al resto di SQL.

Il pattern Postgres-with-JSONB vince quando a volte ti servono query relazionali e a volte query in stile documento (mescolare le due cose in MongoDB è scomodo; in Postgres è una sola query), quando vuoi un solo engine invece di due (backup, monitoring, failover ed expertise separati sono un costo reale), o quando la maggior parte dei tuoi dati è strutturata ma una piccola parte è davvero flessibile.

Il percorso del puro document store vince quando l’intera forma dei dati è davvero flessibile, quando i pattern di accesso sono document-shaped da capo a piedi con pochissime operazioni cross-document, o quando sei in greenfield con l’expertise operativa e un team a suo agio con l’ecosistema.

La diagnostica onesta per il 2026: se non sei sicuro, vai di default su Postgres con JSONB. La via di fuga (spostare le parti JSON in un vero document store dopo) resta aperta. La migrazione inversa (da MongoDB a Postgres) è più dura, perché i dati sono stati scritti sotto un’assunzione di no-fixed-schema che potrebbe aver prodotto inconsistenze di cui non sapevi l’esistenza.

flowchart LR
    subgraph Document_Model
        D[blog_post document]
        D --> Dt[title]
        D --> Da[author embedded]
        D --> Dc[comments array embedded]
        D --> Dg[tags array embedded]
    end
    subgraph Relational_Model
        P[posts row]
        P -.fk.-> U[users row]
        P -.fk.-> C[comments rows]
        P -.fk.-> T[post_tags rows]
        T -.fk.-> Tg[tags rows]
    end

La stessa entità concettuale, due modelli diversi. Nessuno dei due è universalmente giusto. Il modello a documenti è una fetch, una write, un confine di consistency. Il modello relazionale è più righe, più join, più flessibilità per query che il designer originale non aveva previsto.

Gli altri document store

MongoDB è il document store canonico ma non l’unico. Couchbase ha un linguaggio di query simile a SQL (N1QL) ed è forte sui workload single-document a high throughput. RavenDB è un document store sbilanciato verso .NET con un forte focus ACID. Firestore (Google Cloud) è un document store gestito con sync realtime, che calza bene per i workload mobile e web tipo “documenti piccoli, tanti client, aggiornamenti realtime”. DocumentDB (AWS) parla il wire protocol di MongoDB ma sotto è un engine di AWS; la compatibilità è parziale, leggi le clausole in piccolo. CouchDB è il vecchio progetto Apache che ha aperto la strada ad alcuni dei pattern, ancora in uso con PouchDB per applicazioni web offline-first.

Il trade-off è simile in tutti loro: guadagni storage di documenti naturale, perdi le query ad-hoc cross-entity facili.

La lezione operativa

La lezione più importante dall’arco di MongoDB non è sul modello a documenti in sé. È sul peso relativo del modello dei dati rispetto alla maturità operativa. Le lotte di MongoDB negli anni 2010 non erano dovute al fatto che il modello a documenti fosse sbagliato; erano dovute al fatto che l’engine non aveva ancora costruito le storie di replication, sharding, transazioni e gestione dei fallimenti che il mondo relazionale aveva passato quarant’anni a sistemare. Il MongoDB del 2026 è buono non perché il modello a documenti sia diventato più giusto, ma perché la storia operativa ha finalmente recuperato.

Il corollario si generalizza: quando scegli un database, il modello dei dati conta meno di quanto la gente pensi, e la maturità operativa conta di più. Una calzata perfetta del modello dei dati su un engine immaturo produce un outage. Una calzata mediocre su un engine battle-tested produce attrito nel codice applicativo. L’attrito è più economico.

Dove atterra questa lezione

I document store sono legittimi, con una calzata più stretta di quanto il discorso degli anni 2010 suggerisse. MongoDB è l’esempio canonico, e il prodotto è significativamente migliore della sua reputazione di un decennio fa. Postgres con JSONB copre la maggior parte degli use case per cui il modello a documenti veniva venduto, mantenendo SQL a portata di mano per le query in cui il modello a documenti è scarso. Il default onesto nel 2026 è ancora Postgres; il document store si tira fuori quando il workload è genuinamente document-shaped da capo a piedi.

Il prossimo grande modello di dati è il wide-column (Cassandra, ScyllaDB, HBase, Bigtable), che copriamo nella lezione 20. Dopo, time-series (lezione 21), search (lezione 22), graph (lezione 23), e infine la sintesi: lezione 24 sulla polyglot persistence, l’architettura realistica per i sistemi di produzione, che consiste nell’usare il giusto store specialista per ogni forma di dato, con un piccolo insieme di confini ben definiti fra di loro.

Citazioni e letture ulteriori

  • The MongoDB documentation, https://www.mongodb.com/docs/ (retrieved 2026-05-01). Especially the “Transactions”, “Schema Validation”, and “Replication” sections.
  • Kyle Kingsbury, “Jepsen: MongoDB” reports across the years, https://jepsen.io/analyses (retrieved 2026-05-01). The 2013, 2015, 2017, and 2020 reports, read in order, are an education in how a distributed database matures. Read the most recent one for the current state, but the older ones are the more interesting story.
  • Werner Vogels, “Eventually Consistent”, Communications of the ACM, January 2009. Useful background on the consistency models that shaped the early NoSQL movement, MongoDB included.
  • Alex Petrov, “Database Internals” (O’Reilly, 2019). The chapter on storage engines covers the data-structure tradeoffs underneath document stores, key-value stores, and relational databases in a uniform vocabulary.
  • The PostgreSQL JSONB documentation, https://www.postgresql.org/docs/current/datatype-json.html (retrieved 2026-05-01). The reference for the SQL-with-JSONB option, including indexing, operators, and JSONPath.
Cerca