NoSQL e MongoDB

partire_leggeri

MongoDB

Oggi parleremo dei database NoSQL e di un database NoSQL open source tra i più diffusi, MongoDB.

Per prima cosa bisogna definire che cos’è un database NoSQL. Innanzitutto un database NoSQL non è un database relazionale:

  • Non utilizza SQL per eseguire query
  • potrebbe non rispettare le proprietà ACID cioè Atomicità, Consistenza, Isolamento e Persistenza (Durability)
  • solitamente non ha bisogno di uno schema
  • E’ una tecnologia meno matura rispetto ai database relazionali

Non essendo questa la sede più adatta per trattare le proprietà ACID, rimandiamo alla pagina di wikipedia per ulteriori informazioni su queste quattro proprietà caratteristiche dei database relazionali comunemente utilizzati.

I vantaggi dei database NoSQL

  • Scalabilità in orizzontale
  • Migliori performance di lettura/scrittura
  • Superamento delle limitazioni dettate dallo schema
  • Possibilità di definire query complesse utilizzando un linguaggio che non è SQL
  • Possibilità di processare parallelamente i dati (Map-Reduce)
  • Maggior facilità nel replicare la base di dati per fornire ulteriore certezza di disponibilità dei dati
  • Tipi di dato più flessibili

Esaminando i vantaggi, si nota subito come la forza e quindi il campo d’applicazione principale dei database NoSQL sia laddove c’è bisogno di lavorare con dati di dimensioni molto grandi, oppure dove le prestazioni sono critiche (sistemi real-time che possono andare dai giochi alle macchine HFT utilizzate per la compravendita di titoli in borsa in ambito finanziario).

MongoDB

E’ un database, o meglio una suite dato che presenta alcuni tools legati al database stesso (si noti che è comunque una suite snella, nulla a che vedere con le mastodontiche suite con migliaia di funzionalità offerte da Microsoft e Oracle assieme ai loro database relazionali) orientata ai documenti.

Presenta una shell quale strumento di amministrazione ed alcuni driver per l’interfacciamento con i più noti linguaggi di programmazione (esistono poi framework che wrappano al loro interno i driver stessi, ed è consigliato utilizzare questi ultimi in quanto risparmiano parte del lavoro). Inoltre all’interno della shell possiamo trovare strumenti per il profiling, per il backup, eccetera.

E’ anche presente una web I (va attivata mettendo nel file di configurazione rest=true e si trova a localhost:28017), che non permette di interagire col database ma solo di monitorarlo.

Caratteristiche fondamentali di MongoDB

  • document oriented (i documenti sono scritti in JSON)
  • esistenza di indici
  • possibilità di replicazione in modo da fornire alta scalabilità e affidabilità
  • possibilità di eseguire query/update
  • possibilità di eseguire operazioni complesse
  • elaborazione/aggregazione tramite paradigma Map-Reduce e codice Javascript
  • non esiste nessuno schema, è più flessibile e può essere facilmente trasformato in oggetti

La struttura di un database MongoDB

Le collezioni

Un database MongoDB è costituito da un’insieme di collezioni, che sono dei dati accumunati tra loro da una qualche parentela logica, analogamente a quanto accade con le tabelle di un database relazionale.

A differenza di queste ultime però, nelle quali i dati (le righe) che contengono hanno tutti lo stesso formato o meglio lo stesso schema, i dati contenuti in una collezione sono totalmente indipendenti uno dall’altro: mentre una tabella “Anagrafica” in un database relazionale conterrà righe tutte uguali con nome, cognome, età, eccetera, in una collezione potrebbe esserci un elemento con nome,cognome,età ed un altro con solo l’età ed un altro ancora con nome,cognome,data di nascita ma non età.

Ovviamente questo permette una certa libertà ma bisogna fare attenzione ad inserire i dati in maniera tale che gli applicativi riescano poi ad estrarli ed elaborarli quando necessario.

Documenti

Un documento è grosso modo un record (anche detto riga o tupla) di un database relazionale. A differenza dei database relazionali però un documento può contenere al suo interno altri documenti (documenti incorporati). La dimensione massima di un documento in MongoDB è 16 Mb.

Campi

Sono equivalenti ai corrispettivi dei database relazionali, definiscono un singolo elemento all’interno di un documento.

MongoDB: il primo utilizzo

(La guida è intesa per l’utilizzo sotto Windows, sotto altri sistemi operativi le modifiche saranno minime). Ipotizzo di aver installato MongoDB su d:\mongodb\

Il file di configurazione

Per prima cosa occorre preparare un file di configurazione, con il blocco note creare un file config.mongodb e salvarlo nella cartella
d:\mongodb\bin.

E’ obbligatorio all’interno di quel file impostare il percorso dei database, con una linea del genere:

dbpath=d:\mongodb\data

E’ possibile poi aggiungere ulteriori impostazioni di configurazione, come l’attivazione della web ui o altro, per vedere tutti i dettagli vi rimando alla documentazione ufficiale di MongoDB.

Avvio del demone

A questo punto basterà lanciare l’eseguibile del demone, specificando il path del file di configurazione (se si trovano nella stessa cartella basta il nome del file, senza percorso)

d:\mongodb\bin\mongod.exe –config config.mongodb

Avvio della shell e comandi base

Eseguendo d:\mongodb\bin\mongo.exe si aprirà la shell.

MongoDB shell version: 2.2.3
connecting to: test
>

A questo punto è possibile iniziare a lavorare sul nostro database utilizzando la sintassi dei comandi di MongoDB.

Comandi MongoDB

  • use nome_del_database imposta il database attivo, creandolo se non esiste
  • db.getCollectionNames() restituisce la lista di tutte le collezioni per il database in uso
  • db.nome_collezione.insert(documento) per inserire nella collezione nome_collezione un documento. Il documento avrà una sintassi del tipo {name:’pippo’, eta:’f’, saldo:450}
  • db.nome_collezione.find([selettore][,filtro]) è una query, restituisce tutti i documenti presenti nella collezione nome_collezione il *selettore è opzionale, ed appunto serve a selezionare solo alcuni documenti/campi tra quelli presenti all’interno della collezione, l’ultimo parametro invece definisce quali campi restituire e quali no, è anch’esso opzionale ed ha una sintassi del tipo { name:1, id: 0 }
  • ad un comando find() posso aggiungere in coda altri comandi, es. db.nome_collezione.sort({weight:-1, name:1}).limit(2).skip(1) per rispettivamente ordinare, limitare e saltare documenti dalla lista dei documenti restituiti dal find()
  • db.nome_collezione.remove() ripulisce la collezione di tutti i documenti
  • db.nome_collezione.count() restituisce il numero dei documenti nella collezione
  • db.nome_collezione.update(*selettore,riga_sostituiva,upsert, non_fermarti_al_primo_update) l’update ha una sintassi alquanto strana, innanzitutto gli ultimi 2 parametri sono booleani, il primo indica di tentare l’insert e se l’objectid esiste già procedere con un update, mentre il secondo è un nuovo documento o un insieme di campi da aggiornare, se voglio aggiornare dei campi il secondo parametro avrà una sintassi del tipo {$set: {campo1:’newValue’}} . Notare che oltre a $set è possibile utilizzare $inc oppure $push che inserisce un nuovo elemento in un campo di tipo array
  • db.nome_collezione.ensureIndex({primoindice:1, secondoindice: -1}) per inserire un indice (anche composto da più campi e db.nome_collezione.dropIndex({primoindice:1}) per cancellare un indice

*esempi di selettore:

  • {age:30}
  • {age: {$gt 10} }
    dove gt sta per greater than (più grande di), ed è sostituibile con $gte (maggiore o uguale a), $lt (minore di), $lte (minore o uguale a)
  • selettori sull’esistenza di un campo,{‘nome_campo’:{$exists:true}}

Ed il join?

Venendo dai database relazionale questo concetto sembra incredile, ma in MongoDB non esiste il join tra collezioni. Se vogliamo implementare qualcosa di simile occorre farlo a livello di applicativo, non di database: programmiamo due query, la seconda delle quali dipende dal risultato della prima.

Una valida alternativa al join effettuato tramite l’applicazione è la denormalizzazione dei dati, inserisco campi aggiuntivi o documenti incorporati, ottenendo un database che non è più in forma normale (presenterà dipendenze funzionali)., ma non necessita un join.

Le relazioni molti-a-molti o uno-a-molti si implementano inserendo un ObjectId quale valore del campo (es. {nome:’pippo’, padre: ObjectId(“77tfsdygfdsg”) } , ed è anche possibile utilizzare un array cioè {nome:’pippo’, genitori: [ ObjectId(“77tfsdygfdsg”) , ObjectId(“jdshfudhg”) ] }.

Altre feature di MongoDB

Esistono altre feature interessanti implementate in MongoDB che non sono state trattate in questa breve panoramica. Le elenco qua per permettervi di effettuare ricerche su Google o nella documentazione ufficiale per scoprire come sfruttare a fondo questo database NoSQL.

  • Possibilità di utilizzare la struttura a documenti incorporati all’interno di selettori, ad esempio: db.anagrafica.find({‘famiglia.madre’ : ‘tiziana’})
  • Possibilità di eseguire riferimenti da una collezione ad un’altra utilizzando DBREF
  • Possibilità di eseguire elaborazioni in parallelo grazie al paradigma map-reduce
  • Possibilità di eseguire transazioni con la tecnica del commit a 2 fasi
  • Possibilità di capire quali indici utilizza una query post-ponendo ad un comando find() il comando explain() (es. db.nome_collezione.find().explain() )
  • Possibilità di eseguire backup, esportazioni (anche in csv) e restore utilizzando gli strumenti mongodump e mongorestore
  • journaling (attivabile con journal=true nel file config *), soprattutto se ho un singolo nodo e niente repliche, è molto importante, riduce le prestazioni ma aumenta affidabilità.
Esistono molti libri (in inglese) su MongoDB. Non ho ancora avuto l’occasione di leggerne nessuno, vedendo le recensioni su Amazon non c’è un titolo che domina su tutti gli altri, penso che i più validi siano i seguenti (essendo MongoDB un database fondamentalmente semplice da utilizzare la maggior parte dei libri sono molto brevi, meno di 100 pagine, non rimanete delusi se il libro è più sottile di quanto ve lo aspettavate):

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *