Modellazione dei dati

Quando si utilizza MongoDB, o in generale la maggioranza dei database NoSQL, la modellazione dei dati è una fase molto delicata dello sviluppo di una soluzione software. Infatti, a differenza di database relazionali, per cui esiste una vasta letteratura e molti strumenti software per la modellazione dei dati, qui esistono principalmente delle best practice, che derivano dal buon senso e da considerazioni che riguardano non tanto la struttura stessa dei dati, quanto piuttosto il loro utilizzo. Questo significa che a guidare la modellazione dei dati con MongoDB non è tanto la logica insita nei dati stessi, bensì soprattutto il modo in cui le applicazioni li useranno.

Vediamo ora la struttura di un documento: poiché MongoDB è un database schema-less, per definizione non c’è alcuno schema fisso per ogni documento; anzi, ogni documento ha uno schema a sé e le collezioni possono avere dati molto diversi fra loro.

Questo significa che non dobbiamo fare delle scelte a priori su una collection, ma ogni volta che dobbiamo salvare un documento in MongoDB dobbiamo fare delle scelte. La scelta più importante, considerando che in MongoDB non esistono vincoli di integrità referenziale tra i documenti, è come modellare le relazioni tra i documenti. Ci sono due possibilità, ognuna con i suoi pro e contro: documenti incorporati e documenti referenziati.

Documenti incorporati

Questa struttura prevede di incorporare un documento collegato in un campo del documento che lo referenzia. Ad esempio:

{

    titolo: ‘La commedia’,

    autori: [{ nome: ‘Dante’, cognome: ‘Alighieri’ }],

    edizioni: [

        { isbn: ‘xxxxxxx’, anno: 2014, casaEditrice: ‘Edizioni X’, prezzo: 35.50, ultima: true },

        { isbn: ‘yyyyyyy’, anno: 2013, casaEditrice: ‘Edizioni X’, prezzo: 33.20 }

    ]

}

In questo documento abbiamo incorporato ben due altri documenti: autori ed edizioni. Il primo ha una relazione di molti-a-molti, il secondo ha una relazione uno-a-molti.

Vantaggi: atomicità e letture

Il vantaggio principale dell’incorporazione è la gestione dell’atomicità. Infatti per MongoDB le uniche operazioni atomiche sono quelle che coinvolgono un singolo documento: in altre parole, non è possibile effettuare transazioni che coinvolgono due o più documenti. Quindi, salvando tutto il documento, avremo la garanzia che la nostra modifica è effettivamente avvenuta senza il rischio che salvataggi concorrenti abbiano messo il nostro database in uno stato non coerente. Ad esempio abbiamo la garanzia che, anche in caso di letture/scritture concorrenti, ci sarà una sola edizione con il campo ultima impostato a true.

Un altro vantaggio è il numero di letture: per avere le informazioni necessarie su un elemento del nostro database ci basterà una sola lettura, il che è comodo soprattutto in caso di sharding, ossia quando avremo suddiviso le nostre collezioni e distribuite in diversi nodi di MongoDB. In tal caso, infatti, non dovremo interrogare diversi nodi per mettere insieme le informazioni su un’entità della nostra applicazione. Ciò è particolarmente apprezzato quando si sviluppa con paradigmi come DDD (Domain Driven Design) e CQRS (Command and Query Responsibility Segregation).

Svantaggi: relazioni molti-a-molti

Lo svantaggio più grande riguarda invece la ridondanza, principalmente nel caso di relazioni molti-a-molti. Se ad esempio volessimo inserire un’altra opera dello stesso autore nel database, dovremmo replicare tutte le informazioni sull’autore. Se tali informazioni sono poche, il danno è minimo; se invece sono tante potremmo far crescere rapidamente il nostro database. Inoltre, se volessimo aggiornare uno dei dati di un autore dovremmo effettuare un aggiornamento massivo su tutti i documenti che incorporano l’autore da aggiornare. Ad esempio:

db.opere.update(

                             { “autori.cognome”: “Alighieri” },

                             { $set: { “autori.0.natoA”: “Firenze” }},

                             { multi: true}

                           );

Anche qui, se il database ha dimensioni contenute, l’aggiornamento sarà rapido; altrimenti, esso potrà richiedere diverso tempo. Inoltre non c’è nessun meccanismo che garantisca che lo stesso autore incorporato in due documenti diversi contenga esattamente gli stessi dati.

Documenti referenziati

Le relazioni tra documenti possono essere rappresentate anche tramite l’indicazione di una chiave o un identificativo che permette di collegarli. Ciò significa che avremo più documenti che condividono dei riferimenti tra loro. L’esempio precedente viene quindi spezzato in quattro documenti:

{

    titolo: ‘La commedia’,

    autori: [ ‘dante’ ],

    edizioni: [ ‘xxxxxxx’, ‘yyyyyyy’ ]

}

{ _id: ‘dante’, nome: ‘Dante’, cognome: ‘Alighieri’ }

{ _id: ‘xxxxxxx’, anno: 2014, casaEditrice: ‘Edizioni X’, prezzo: 35.50, ultima: true },

{ _id: ‘yyyyyyy’, anno: 2013, casaEditrice: ‘Edizioni X’, prezzo: 33.20 }

Ovviamente ha senso suddividere questi documenti in tre collezioni: opere, autori, edizioni.

Svantaggi: numero di letture e consistenza

Lo svantaggio maggiore è nel numero di letture: infatti per ricostruire i dati di un documento coinvolto in una relazione dobbiamo effettuare tante letture quanti sono i documenti referenziati.

Dobbiamo anche notare che nei campi edizioni ed autori abbiamo semplicemente un array di valori: MongoDB non è affatto consapevole del fatto che essi si riferiscano a documenti effettivamente esistenti in altre collezioni. Ciò perché non esiste il concetto di relazione ed integrità referenziale

Riepilogando, non è possibile fornire una regola generale di modellazione dei dati, ma bisogna valutare caso per caso, in base all’utilizzo che si farà del database ed alle esigenze delle applicazioni. Però si può dire che:

  •  l’utilizzo di documenti incorporati è più indicato in caso di relazioni uno-a-molti;
  •  l’utilizzo di documenti referenziati è più indicato in caso di relazioni molti-a-molti.
PHP Code Snippets Powered By : XYZScripts.com