Come già scritto, non ci sono regole come la seconda forma normale per SQL.
Tuttavia, ci sono alcune best practice e insidie comuni relative all'ottimizzazione per MongoDB che elencherò qui.
Uso eccessivo dell'incorporamento
Il limite BSON
Contrariamente alla credenza popolare, non c'è niente di sbagliato nei riferimenti. Supponi di avere una biblioteca di libri e di voler tenere traccia degli affitti. Potresti iniziare con un modello come questo
{
// We use ISBN for its uniqueness
_id: "9783453031456"
title: "Schismatrix",
author: "Bruce Sterling",
rentals: [
{
name:"Markus Mahlberg,
start:"2015-05-05T03:22:00Z",
due:"2015-05-12T12:00:00Z"
}
]
}
Sebbene ci siano diversi problemi con questo modello, il più importante non è ovvio:ci sarà un numero limitato di noleggi a causa del fatto che i documenti BSON hanno un limite di dimensione di 16 MB.
Il problema della migrazione dei documenti
L'altro problema con la memorizzazione dei noleggi in un array sarebbe che ciò causerebbe migrazioni di documenti relativamente frequenti, operazione piuttosto costosa. I documenti BSON non vengono mai partizionati e creati con uno spazio aggiuntivo allocato in anticipo utilizzato quando crescono. Questo spazio aggiuntivo è chiamato riempimento. Quando il riempimento viene superato, il documento viene spostato in un'altra posizione nei file di dati e viene allocato nuovo spazio di riempimento. Pertanto, le frequenti aggiunte di dati causano frequenti migrazioni di documenti. Pertanto, è consigliabile evitare che aggiornamenti frequenti aumentino le dimensioni del documento e utilizzare invece i riferimenti.
Quindi, per l'esempio, cambieremmo il nostro singolo modello e ne creeremmo un secondo. Innanzitutto, il modello per il libro
{
_id: "9783453031456",
title:"Schismatrix",
author: "Bruce Sterling"
}
Il secondo modello per il noleggio sarebbe simile a questo
{
_id: new ObjectId(),
book: "9783453031456",
rentee: "Markus Mahlberg",
start: ISODate("2015-05-05T03:22:00Z"),
due: ISODate("2015-05-05T12:00:00Z"),
returned: ISODate("2015-05-05T11:59:59.999Z")
}
Lo stesso approccio ovviamente potrebbe essere utilizzato per l'autore o per l'affittuario.
Il problema dell'eccessiva normalizzazione
Guardiamo indietro un po' di tempo. Uno sviluppatore identificherebbe le entità coinvolte in un business case, definirebbe le loro proprietà e relazioni, scriverebbe le classi di entità corrispondenti, sbatterebbe la testa contro il muro per alcune ore per ottenere il triplo interno-esterno-sopra e oltre JOIN richiesto per il caso d'uso e tutti vissuti felici e contenti. Allora perché usare NoSQL in generale e MongoDB in particolare? Perché nessuno visse per sempre felici e contenti. Questo approccio scala orribilmente e quasi esclusivamente l'unico modo per scalare è verticale.
Ma la principale differenza di NoSQL è che modelli i tuoi dati in base alle domande a cui devi ottenere risposta.
Detto questo, diamo un'occhiata a una tipica relazione n:m e prendiamo come esempio la relazione tra autori e libri. In SQL, avresti 3 tabelle:due per le tue entità (libri e autori ) e uno per la relazione (Chi è l'autore di quale libro? ). Naturalmente, potresti prendere quei tavoli e creare le loro raccolte equivalenti. Ma, poiché non ci sono JOIN in MongoDB, avresti bisogno di tre query (una per la prima entità, una per le sue relazioni e una per le entità correlate) per trovare i documenti correlati di un'entità. Questo non avrebbe senso, dal momento che l'approccio a tre tabelle per le relazioni n:m è stato specificamente inventato per superare i rigidi schemi imposti dai database SQL. Poiché MongoDB ha uno schema flessibile, la prima domanda sarebbe dove archiviare la relazione, mantenendo i problemi derivanti dall'uso eccessivo dell'incorporamento in mente. Poiché un autore potrebbe scrivere parecchi libri negli anni a venire, ma la paternità di un libro cambia raramente, se non del tutto, la risposta è semplice:memorizziamo gli autori come riferimento agli autori nei dati dei libri
{
_id: "9783453526723",
title: "The Difference Engine",
authors: ["idOfBruceSterling","idOfWilliamGibson"]
}
E ora possiamo trovare gli autori di quel libro facendo due domande:
var book = db.books.findOne({title:"The Difference Engine"})
var authors = db.authors.find({_id: {$in: book.authors})
Spero che quanto sopra ti aiuti a decidere quando effettivamente "dividere" le tue collezioni e ad aggirare le insidie più comuni.
Conclusione
Per quanto riguarda le tue domande, ecco le mie risposte
- Come scritto prima:No , ma tenendo presenti i limiti tecnici dovrebbe darti un'idea di quando potrebbe avere senso.
- Non è male, purché si adatti ai tuoi casi d'uso . Se hai una determinata categoria e il suo
_id
, è facile trovare i prodotti correlati. Quando carichi il prodotto, puoi facilmente ottenere le categorie a cui appartiene, anche in modo efficiente, come_id
è indicizzato per impostazione predefinita. - Devo ancora trovare un caso d'uso che non possa essere fatto con MongoDB, anche se alcune cose possono diventare un po' più complicate con MongoDB. Quello che dovresti fare imho è prendere la somma dei tuoi requisiti funzionali e non funzionali e verificare se i vantaggi superano gli svantaggi. La mia regola pratica:se uno tra "scalabilità" o "alta disponibilità/failover automatico" è nell'elenco dei requisiti, MongoDB vale più di un'occhiata.