f in x
Modello Documentale MongoDB: Schema Design tra Embedding e Referencing
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Analisi dei dati e metriche

Modello Documentale MongoDB: Schema Design tra Embedding e Referencing

[2026-06-08] Author: Ing. Calogero Bono

Hai un database relazionale e pensi che MongoDB sia solo «senza schema»? Oppure hai già MongoDB ma i dati sono un groviglio di lookup e documenti annidati come scatole cinesi. Il problema è sempre lo stesso: scegliere tra embedding e referencing è la decisione più importante del modello documentale. Sbagliare significa query lente, crescita di dati fuori controllo o operazioni atomiche impossibili. Noi, di Meteora Web, ci siamo passati: abbiamo progettato documenti per piattaforme SaaS, e-commerce e sistemi di inventory. Veniamo dalla contabilità e dall'ERP, dove lo schema dei dati è un bilancio: se non è pensato bene, il report finale non torna.

Il modello documentale non è «senza schema»

MongoDB non ha uno schema fisso al livello di tabella, ma ogni documento ha una struttura che deve essere progettata come in un database relazionale, solo con regole diverse. La prima differenza: i dati correlati possono stare dentro lo stesso documento (embedding) o in documenti separati con riferimenti (referencing).

L'errore comune: «Vado di embedding, tanto MongoDB lo gestisce». Invece l'embedding eccessivo produce documenti enormi, supera il limite di 16 MB, o costringe a riscrivere tutto per un aggiornamento parziale. Il referencing esagerato invece moltiplica le query e appesantisce il database di $lookup.

Embedding: quando e perché

Embedding significa inserire un sotto-documento o un array direttamente nel documento principale. Si usa quando:

  • I dati sono letti insieme quasi sempre (es. indirizzo di un utente e i suoi ordini recenti).
  • La cardinalità è uno-a-uno o uno-a-pochi.
  • L'aggiornamento è atomico sull'intero documento.

Esempio pratico: un blog con articoli e commenti. I commenti sono pochi per articolo e vengono letti insieme all'articolo. Li embeddiamo:

{
  "_id": ObjectId("..."),
  "title": "Impara MongoDB",
  "content": "...",
  "comments": [
    { "author": "Mario", "text": "Ottimo articolo", "date": ISODate("2025-03-01") },
    { "author": "Luigi", "text": "Grazie!", "date": ISODate("2025-03-02") }
  ]
}

Con un solo find otteniamo articolo e commenti. Nessuna join. Però attenzione: se i commenti crescono a migliaia per articolo, superiamo il limite di 16 MB e le performance di aggiornamento diventano un incubo. Regola pratica: array embeddati con dimensione prevista sotto il centinaio di elementi.

Referencing: quando e perché

Referencing significa salvare l'ID di un altro documento nel campo e poi eseguire un $lookup per recuperarlo. Si usa quando:

  • I dati vengono aggiornati spesso indipendentemente (es. profilo utente e ordini).
  • La cardinalità è uno-a-molti o molti-a-molti.
  • Il documento padre non deve essere riscritto ogni volta che un figlio cambia.

Esempio pratico: un e-commerce con ordini e prodotti. Un prodotto può apparire in milioni di ordini. Embeddare l'intero prodotto in ogni ordine sarebbe follia: usiamo referencing.

// Documento Ordine
{
  "_id": ObjectId("ord123"),
  "user_id": ObjectId("user456"),
  "items": [
    { "product_id": ObjectId("prod789"), "quantity": 2, "price": 19.99 },
    { "product_id": ObjectId("prod012"), "quantity": 1, "price": 29.99 }
  ],
  "total": 69.97
}

// Documento Prodotto (separato)
{
  "_id": ObjectId("prod789"),
  "name": "T-shirt",
  "price": 19.99,
  "stock": 50
}

Per ottenere l'ordine con i dettagli prodotto usiamo una pipeline di aggregazione:

db.orders.aggregate([
  { $match: { _id: ObjectId("ord123") } },
  { $unwind: "$items" },
  { $lookup: {
      from: "products",
      localField: "items.product_id",
      foreignField: "_id",
      as: "product_details"
  } },
  { $group: { _id: "$_id", items: { $push: { item: "$items", product: { $first: "$product_details" } } } } }
])

I $lookup non sono gratuiti: impattano sulle performance se non si indicizzano i campi coinvolti. Indicizza sempre localField e foreignField.

Ereditarietà e pattern relazionali in MongoDB

Non esiste una regola fissa: decidere è un compromesso. Noi usiamo una griglia decisionale semplice:

  • Embedding se la relazione è «contiene e vive insieme».
  • Referencing se la relazione è «si riferisce ma vive separato».
  • Embedding + schema ibrido quando un sotto-insieme di dati può essere duplicato per performance (es. nome prodotto in un ordine, anche se poi cambia). È il pattern «pre-join».

Errore da evitare: pensare che l'embedding sia sempre meglio perché evita i lookup. Abbiamo visto progetti con documenti da 100KB contenenti array di decine di migliaia di elementi: ogni aggiornamento riscriveva l'intero documento, portando a conflitti di concorrenza e rallentamenti. In quei casi, via ai riferimenti con lookup ben indicizzati.

Operazione pratica: valutare la tua entità

Per ogni coppia di entità, rispondi a queste domande:

  1. Quante volte vengono lette insieme? (% delle query)
  2. Quanto spesso cambiano i dati del «figlio» indipendentemente?
  3. Qual è il rapporto di cardinalità massimo previsto? (pochi/milioni)
  4. Il documento padre deve essere aggiornato atomicamente con i figli?

Se risposte puntano a lettura quasi sempre insieme, cambiamenti rari, cardinalità bassa e necessità atomica → embedding. Altrimenti → referencing.

Pattern avanzati: ibride e pre-join

Talvolta la scelta giusta è un ibrido: mantenere pochi campi del figlio embeddati (quelli letti sempre) e il resto in referencing. Esempio classico: profilo utente con il suo ultimo login embeddato, mentre la cronologia completa è in un'altra collezione.

{
  "_id": ObjectId("user123"),
  "name": "Mario",
  "email": "mario@example.com",
  "last_login": ISODate("2025-03-10T12:00:00Z"),  // embeddato
  // storage degli ordini completi via referencing
}

Questo pattern bilancia performance e mantenibilità. Noi lo abbiamo applicato in un sistema di fatturazione: ogni fattura conteneva i dati del cliente al momento dell'emissione (nome, partita IVA) embeddati, ma il cliente poteva cambiare indirizzo in futuro senza alterare le fatture passate.

Ottimizzazione delle query con embedding ben progettato

L'embedding non è solo una scelta di schema: è una strategia di performance. Quando embeddiamo, possiamo indicizzare i campi annidati con dot notation:

db.articles.createIndex({ "comments.author": 1 })

Eseguire query dirette senza aggregation:

db.articles.find({ "comments.author": "Mario" })

Il limite: l'indice su campo annidato non supporta range su più valori se l'array è grande. Per array enormi, meglio sganciare in una collezione separata.

In sintesi — cosa fare adesso

  1. Analizza le tue query principali: prendi le top 10 query di lettura e scrivi quali entità coinvolgono. Se più del 70% le legge insieme, embedding è favorito.
  2. Stima la cardinalità: se un genitore può avere più di qualche centinaio di figli, vai di referencing. Se sono poche decine, embedding.
  3. Progetta il documento come se fosse una view: chiediti «cosa voglio ottenere con una sola query?». Se la risposta è «tutto», embedda. Ma se devi aggiornare frequentemente un campo figlio, riferiscilo.
  4. Testa con dati reali: genera un milione di documenti e misura il tempo di query con embedding vs referencing. Non fidarti della teoria.
  5. Indicizza tutto ciò che filtro: sia su campi embeddati (dot notation) sia su campi referenziati (localField).

Se hai dubbi, parti da una struttura referenziata e embedda solo per famiglie di dati che non cambiano spesso. È più facile aggiungere embedding che toglierlo.

Noi di Meteora Web progettiamo modelli documentali ogni giorno. Se hai un progetto MongoDB e vuoi evitare di ritrovarti con un database che rallenta dopo tre mesi, contattaci. Ti aiutiamo a progettare lo schema giusto, con la stessa attenzione che mettiamo nei bilanci delle PMI.

Sponsored Protocol

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Co-founder di Meteora Web. Ingegnere informatico, sviluppo ecosistemi digitali ad alte prestazioni. AI, automazione, SEO tecnica e infrastrutture web. Scrivo di tecnologia per rendere complesso… semplice.

[ Read Full Dossier ]

Hai bisogno di applicare questa strategia?

Esegui il protocollo di contatto per iniziare un progetto con noi.

> INIZIA_PROGETTO

Sponsored

> MW_JOURNAL

> READ_ALL()