Modellizzazione database - embedding

30 views
Skip to first unread message

Nicola Mondello

unread,
Apr 1, 2014, 6:07:05 AM4/1/14
to mongo...@googlegroups.com
Ciao a tutti, sto usando per la prima volta mongoDB; qualcuno mi puo' confermare se quello che ho capito e' giusto?
ho letto che in mongoDB si usa fare l'embedding con sottodocumenti o array di sottodocumenti per risparmiare tempo in lettura, ad esempio se ho Libro ed Autore con i DB relazionali avrei fatto due tabelle separate e poi dentro la tabella Libro mettevo come chiave esterna l'id dell'autore; in mongoDB invece metto tutte le info dell'autore (o solo le + frequenti) direttamente in un campo della collection Libro (sottodocumento).
La mia domanda e': la collection Autore la devo fare lo stesso giusto? se un giorno volessi solo visualizzare tutti gli autori ovviamente mi serve questa collection, quindi l'embedding consiste nel duplicare i dati che si accedono piu' di frequente per risparmiare tempo in lettura, giusto? La fregatura sta che se voglio aggiungere o modificare un campo dell'autore devo farlo tante volte per quanti libri hanno quell'autore + 1 per la collection Autore, giusto? (di norma queste modifiche hanno ordini di frequenza minori/molto minori delle letture quindi e' un overhead accettabile).
Sbaglio qualcosa?

Stefano Cudini

unread,
Apr 1, 2014, 12:38:42 PM4/1/14
to mongo...@googlegroups.com
anche se non sono espertissimo di mongodb.. cmq posso dirti che è tutto esatto, nonostante le poche esperienze che ho avuto ti posso dire che molto spesso non è una completa fregatura se si ha l'accortezza di duplicare solo i campi di cui hai quasi la certezza che non subiranno modifiche in futuro.
Ad esempio il campo username in molti sistemi non viene mai modificato xke spesso è usato anche come identificativo univoco oppure non si permette all'utente di modificarlo

Un'altra cosa da tenere bene a mente è che non tutti i documenti di una collection devono essere per forza uguali... anzi spesso si tende a farli uguali solo per abitudine con SQL... ma ho notato che a volte questo è un vantaggio maggior di quello che si pensa!
Message has been deleted

Massimo Brignoli

unread,
Jul 19, 2014, 4:33:08 PM7/19/14
to mongo...@googlegroups.com
Ciao Nicola,

la risposta corretta e' Ni.

Nell'esempio da te portato, tu puoi decidere se avere una collection Libri che embeddano i dati degli autori o la collection Autori i cui documenti embeddano i dati dei libri.

In un relazione questo caso sarebbe rappresentato che 3 tabelle non con due visto che e' una relazione molti a molti. Ma supponiamo, per semplicità, che ci sia un autore solo per ogni libro e che quindi la relazione sia 1 a molti.

Partiamo ad esempio facendo una sola collection Libri:

i documenti sarebbe fatti cosi':

{ _id:123,
titolo: "MongoDB in action",
descrizione:"bla bla bla",
ISBN: "12314",
autore: { Nome, cognome, data nascita, città,  }
}

Ovviamente i dati degli autori vengono duplicati per ogni libro che hanno scritto, quindi se un autore trasloca devi fare l'update di tutti i documenti che contengono i suoi libri.

Se tu dovessi fare 

db.libri.find({},{_id:0,autore:1})

Otterresti l'elenco degli autori ma con elementi duplicati. Per fare una "Distinct" devi usare la funzione aggregate.


Diciamo non molto comodo da gestire.

L'altra opzione e' di fare una collection autori, che sarebbe la tabella padre in una struttura relazionale.

In questo caso i documenti risulterebbero cosi':

{
"_id" : 123,
"nome" : "Massimo",
"cognome" : "Brignoli",
"citta" : "Milano",
"data_nascita" : ISODate("1969-07-11T00:00:00Z"),
"libri" : [
{
"ISBN" : "123",
"titolo" : "A",
"descrizione" : "AAA",
"edizione" : 1
},
{
"ISBN" : "434",
"titolo" : "B",
"descrizione" : "BBB",
"edizione" : 3
}
]
}

In questo caso per modificare i dati di un autore devi fare l'update di un singolo documento. Idem se cambiano i dati di un libro, siccome c'e' un solo autore per libro.

Per trovare l'autore di un libro:

db.autori.find({libri.ISBN: "123"})

per trovare tutti i libri il cui titolo contiene MongoDB

db.autori.find({libri.titolo: /MongoDB/})

Per trovare tutti i libri di un autore:

db.autori.find({nome:"xxx", cognome:"yyy"},{_id:0, libri:1})

I libri pero' ti vengono restituiti in un formato array, un po' brutto da manipolare.

Anche in questo caso ti viene in aiuto la funzione aggregate con gli operatori $match, $unwind e $project

db.autori.aggregate({$match: {nome:"Massimo"}},{ $unwind: "$libri"}, {$project:{ _id:0, libri:1 }}).pretty()
{
"libri" : {
"ISBN" : "123",
"titolo" : "A",
"descrizione" : "AAA",
"edizione" : 1
}
}
{
"libri" : {
"ISBN" : "434",
"titolo" : "B",
"descrizione" : "BBB",
"edizione" : 3
}
}

Elenco dei top autori di libri:

db.autori.aggregate({ $unwind: "$libri"}, {$group: {_id:{nome:"$nome", cognome:"$cognome"}, "libri": {$sum:1}}},{$project: {nome:"$_id.nome",cognome:"$_id.cognome",_id:0,libri:1}},{$sort: {libri:-1}},{$limit:10})

{ "libri" : 2, "nome" : "Massimo", "cognome" : "Brignoli" }

{ "libri" : 1, "nome" : "Nicola", "cognome" : "XXXXX" }

Come vedi con l'aggregate puoi manipolare e rigirare come vuoi il formato dell'output.


Massimo


Reply all
Reply to author
Forward
0 new messages