MongoDB Poccia Silvestro, Trevisani Luca 11 gennaio 2011 Abstract Nel presente documento si presenta MongoDB, una relativamente nuova tecnologia per l’implementazione di un DBMS document-oriented. Il testo nasce dalla curiosità di approfondire un approccio completamente senza schemi, molto lontano dalle classiche implementazioni relazionali che negli anni ci hanno rassicurato con le loro ben definite strutture ma allo stesso tempo imbrigliato in logiche rigide, difficilmente alterabili dopo la fase di progetto. Il nostro documento si articola in tre capitoli fondamentali: 1. Panorama Tecnologico. In questo capitolo si analizza a volo d’uccello il panorama odierno in merito alle tecnologie impiegate per la realizzazione dei DBMS moderni. In particolare si elencano e discutono le caratteristiche peculiari degli approcci relazionali ed ad oggetti. 2. MongoDB. In questo capitolo si presenta il modello document-oriented relativo al MongoDB, per poi introdurre ulteriori scelte architetturali e funzionalità proprie del MongoDB. 3. MongoDB HowTo. In questo capitolo si presentano le principali operazioni effettuabili sul DBMS attraverso le interfacce messe a disposizione da MongoDB, con un approccio pratico, a supporto di un eventuale utilizzo del sistema da parte di un nuovo utente. 4. Conclusioni. Nel capitolo conclusivo si tirano le somme di un eventuale impiego di MongoDB in un sistema reale. Ad integrare il testo due appendici illustrano sinteticamente l’impiego della sintassi JSON per interagire con il sistema e le principali differenze e similitudini con il linguaggio SQL ed il database relazionale MySQL. Indice Elenco delle figure iii Elenco delle tabelle v 1 Panorama Tecnologico 1.1 RDBMS . . . . . . . 1.2 ODBMS . . . . . . . 1.3 OODBMS . . . . . . 1.4 ORDBMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 3 5 7 2 MongoDB 2.1 Document-oriented storage 2.2 Supporto completo Indici . 2.3 Replication . . . . . . . . . 2.4 Auto-Sharding . . . . . . . 2.5 Querying . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 9 11 12 12 14 3 MongoDB HowTo 3.1 Installazione . . . . . . . . . . . . . . . . . . . 3.1.1 Utilizzo avanzato del demone mongod 3.2 Gestione Database . . . . . . . . . . . . . . . 3.2.1 Selezione del database . . . . . . . . . 3.2.2 Creazione del database . . . . . . . . . 3.2.3 Eliminazione del database . . . . . . . 3.3 Gestione Utenti . . . . . . . . . . . . . . . . . 3.3.1 Creazione Utente . . . . . . . . . . . . 3.3.2 Modifica Utente . . . . . . . . . . . . 3.3.3 Eliminazione Utente . . . . . . . . . . 3.3.4 Autenticazione Utente . . . . . . . . . 3.4 Gestione Collezioni . . . . . . . . . . . . . . . 3.4.1 Creazione Collezione . . . . . . . . . . 3.4.2 Creazione Oggetto . . . . . . . . . . . 3.4.3 Modifica Oggetto . . . . . . . . . . . . 3.4.4 Eliminazione Oggetto . . . . . . . . . 3.4.5 Eliminazione Collezione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 15 16 17 18 18 18 20 20 20 20 21 24 25 25 26 28 29 . . . . . . . . . . . . 4 Conclusioni 31 i ii INDICE 5 Appendice 33 5.A Sintassi JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 5.B Migrare da SQL a MongoDB . . . . . . . . . . . . . . . . . . . . 35 Bibliografia 37 Elenco delle figure 1.1 Tecnologie OODBMS . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.1 3.2 Avvio demone mongod . . . . . . . . . . . . . . . . . . . . . . . . Avvio della shell mongo . . . . . . . . . . . . . . . . . . . . . . . 15 16 iii Elenco delle tabelle 3.1 Tabella delle opzioni di modifica . . . . . . . . . . . . . . . . . . 27 5.1 5.2 Tabella tecnica SQL MongoDB . . . . . . . . . . . . . . . . . . . Tabella comparativa SQL-MongoDB . . . . . . . . . . . . . . . . 35 36 v Capitolo 1 Panorama Tecnologico Di necessità virtù è forse l’espressione che meglio riassume i contenuti di questa introduzione, perchè si tratterà l’evoluzione dei DBMS - Database Management System - dagli RDBMS - Relational DBMS - agli ODBMS - Object DBMS. Cosa hanno in comune? Perchè sono nati? In sostanza alla base di un’evoluzione c’è sempre una necessità. Grazie allo sviluppo di internet, i database oggi sono usati più che mai per memorizzare ed accedere alle informazioni in contesti sempre più dinamici e con una forte esigenza di interoperabilità tra sistemi, devono quindi: permettere alle applicazioni di mutare ed evolvere velocemente. consentire alle applicazioni di essere conformi ai nuovi standard de facto o de iure. garantire in ogni caso i capisaldi delle proprietà ACID. Questo ha dato una forte spinta allo sviluppo di tecnologie per i database. Il panorama odierno è dominato da tre classi principali e le zone grigie che le dividono: Relazionale Object-Oriented Object-Relational In questa introduzione ci occuperemo di discutere questi tre modelli evidenziandone i punti di forza ed i loro talloni d’Achille. Nel capitolo successivo si tratterà un ulteriore modello: il Document-Oriented dbms, che esalta le necessità di performance e polimorfismo delle applicazioni di nuova generazione, dove l’utente - non più strettamente vincolato dal sistema - riveste un ruolo centrale nella creazione e gestione dei dati (tipico nel paradigma del web 2.0) e fornisce supporto alle problematiche attuali di labeling delle risorse (fondamentale per il web 3.0 in arrivo). 1 2 CAPITOLO 1. PANORAMA TECNOLOGICO 1.1 RDBMS Si deve ad Edgar F. Codd negli oramai lontani anni 70 la nascita dei database relazionali ; il primo prototipo fu sviluppato da IBM in collaborazione con l’Università di Berkley; vari vendors poterono cosı̀ offrire database relazionali, costruendo la rete di database relazionali che già si prestavano al supporto di applicativi complessi e per i quali era richiesta una certa affidabilità e consistenza dei dati, come quelli di ambito finanziario. Un database è un archivio strutturato in modo tale da consentire l’accesso e la gestione dei dati stessi (l’inserimento, la ricerca, la cancellazione ed il loro aggiornamento) da parte di particolari applicazioni software ad essi dedicate. Il database è un insieme di informazioni, di dati che vengono suddivisi per argomenti in ordine logico (tabelle) e poi tali argomenti vengono suddivisi per categorie (campi). Le tabelle, in un RDBMS, sono collegate fra loro da relazioni. L’uso della teoria degli insiemi consente di strutturare i dati in serie di tabelle composte da colonne (domini). ogni colonna corrisponde a un attributo di quella relazione ogni riga corrisponde a un record che contiene i dati valorizzati per un entità (tupla). Gli RDBMS si basano sui 3 elementi cardini - secondo Ted Codd - per un sistema relazionale: il concetto di relazionale, l’integrità e la normalizzazione. Inoltre è previsto uno standard per l’interrogazione della base dati: SQL Standard Query Language. Lo sviluppo rapidissimo del database relazionale è strettamente legato alle applicazioni per le quali tale modello ha fatto da padrone ovvero quelle finanziarie–bancarie, dove i tipi di dato semplici ed una forte strutturazione delle tabelle in binari vincolanti ben si sposavano con le caratteristiche del modello. Nelle applicazioni d’oggi questa eccessiva rigidità che negli albori del modello rappresentava una caratteristica rassicurante è diventato - in taluni casi - un pesante fardello, se non un vero e proprio limite: pensiamo ad un blog, ci basta gestire dati semplici? stringhe numeri valori booleani date Caratteristica dei blog è che l’utente al centro del processo creativo: mostra se stesso e la propria personalità. Come è possibile fornire in un db relazionale la flessibilità a ciascuna persona per creare contenuti completamente diversi da post a post, siano essi semplici o complessi, più o meno articolati ? Certo un database relazionale ha molti vantaggi: il sistema è semplice, flessibile e produttivo, poichè le tabelle sono semplici, i dati sono semplici per cui facili da capire e da comunicare con gli altri. l’SQL è un linguaggio facile da imparare e soprattutto è uno standard. 1.2. ODBMS 3 I database relazionali hanno però dei limiti, come già affermato, gestiscono solo dati semplici per cui si prestano male alla gestire dati complessi, strutturati al di fuori degli schemi o con un alto tasso evolutivo. Ma questo non basta, un altro limite dei database relazionali è l’inadeguatezza ad operare con linguaggi al di fuori di SQL. Dopo lo sviluppo iniziale degli RDBMS, sono nate applicazioni - scritte maggiormente in c++ e javascript - basate su RDBMS, per le quali era comunque necessario passare per SQL per ottenere i dati e poi trasportarli all’interno degli oggetti dell’applicativo. Questo mismatch lascia un pesante gap tra linguaggio applicativo ed il DBMS relazionale, per cui i database relazionali non funzionano in modo efficiente con questi linguaggi, questo è accettato per aumentare l’astrazione (portabilità). Altro limite è l’esigenza che le informazioni debbano essere in tabelle in cui le relazioni tra entità siano realizzate usando dei valori (vincoli di integrità referenziali, che introducono una complessità strutturale maggiore). Oggi, il modello relazionale è il modello delle basi di dati dominante cosı̀ come la base per i prodotti di punta DBMS. 1.2 ODBMS Sebbene gli RDBMS siano ormai insostituibili nell’ambito delle applicazioni finanziarie, in altri ambiti si sono sviluppati dei modelli più flessibili capaci di gestire dati complessi: gli ODBMS - Object DBMS. I sistemi classici relazionali hanno consentito di realizzare ottimi sistemi gestionali (banche e finanza) caratterizzati da persistenza, condivisione ed affidabilità. Per questi sistemi bastava gestire dati semplici (stringhe, caratteri, numeri). I sistemi relazionali permettevano con la loro sintassi di realizzare query anche molto complesse. Causa la rapida evoluzione tecnica, sono nate delle aree applicative per cui gli RDBMS non erano propriamente adatti. Basti pensare all’archiviazione di immagini, volendo usare un RDBMS le alternative sarebbero: inserire in un campo di una tabella il path dell’immagine. valorizzare un campo col corrispettivo binario dell’immagine. Se questo è il problema che si ritrova per un’immagine pensiamo a quanto cresce in scala se ci occupiamo di archiviazione di foto gestione di codici parlanti videosorveglianza oppure in generale di applicazioni che nella maggior parte dei casi necessitano di gestire dati a struttura complessa. 4 CAPITOLO 1. PANORAMA TECNOLOGICO Se poi si tratta di applicazioni dove l’utente deve poter gestire tipi predefiniti e tipi definiti dall’utente stesso in un approccio dove l’utente diventa centrale nell’applicazione, risulta evidente che l’utilizzo di un RDBMS non sia ottimale. Tutti questi sistemi hanno una caratteristica in comune: tutte le unità fondamentali sono oggetti. Gli oggetti nel paradigma relazionale sono splittati su molte tabelle, pertanto il divario tra oggetto e struttura relazionale è riempito da query molto complesse. L’utilizzo di un paradigma che coinvolga oggetti può risolvere problemi come: la specifica di strutture complesse con relazioni unitarie tra i dati. la descrizione dei dati integrata e le operazioni per il loro recupero. Un rapporto 1:1 con i linguaggi di programmazione ad oggetti. Una base di dati ad oggetti è una collezione di oggetti in cui ogni oggetto ha un identificatore, uno stato ed un comportamento. Stato: insieme dei valori assunti dalle proprietà dell’oggetto. Comportamento: insieme dei metodi che possono essere applicati all’oggetto. OID: identificativo dell’oggetto (in genere non è gestito dall’utente ma gli è invisibile). Nel paradigma ad oggetti ci sono due approcci che, sebbene presentino delle caratteristiche comuni, si presentano rispetto agli schemi relazionali in maniera dissimile: OODBMS - Object-oriented DBMS ORDBMS - Object-relational DBMS Nel paradigma ODBMS un oggetto è un’istanza di un certo tipo. Un tipo definisce le proprietà statiche (attributi) e dinamiche (metodi) dell’oggetto. La complessità strutturale che questo modello offre è garantita proprio dall’uso di costruttori di tipo. Pertanto oggetti che nel mondo reale sono complessi vengono rimarcati dalla strutturazione di un tipo complesso. Una classe è un raccoglitore di oggetti dello stesso tipo. In genere la definizione di una classe si articola in due passi: Interfaccia Implementazione Alla base di un approccio orientato agli oggetti c’è il principio di incapsulamento: l’interfaccia descrive solo le operazioni applicabili sull’oggetto mentre l’implementazione nasconde la struttura dati e il codice interno ai metodi. La persistenza in questi sistemi è una caratteristica trasparente al programmatore. 1.3. OODBMS 1.3 5 OODBMS Gli OODBMS estendono i DBMS a partire dalle caratteristiche dei linguaggi di programmazione ad oggetti, pertanto superano il disadattamento di impedenza che esiste nelle basi di dati relazionali tra i linguaggi in cui sono scritte le applicazioni e l’SQL con cui sono scritte le query per il recupero degli oggetti. Già dai primi anni ’80 per combattere le limitazioni del RDBMS e affrontare la sfida della crescita crescente di Internet e il Web, i programmatori hanno sviluppato database object-oriented. L’obiettivo principale degli Object-Oriented Database Management System, sinteticamente noti come OODBMS, è quello di fornire dati coerenti, indipendenti, sicuri, controllati e servizi estensibili di gestione dati per sostenere il modello orientato agli oggetti. Tra le caratteristiche fondamentali dei database o-o, l’unione di programmazione object-oriented con tecnologia del database fornisce un sistema integrato di sviluppo di applicazioni, portando in questo modello principi distintivi della programmazione orientata agli oggetti: eredità, incapsulamento dei dati, identità dell’oggetto e polimorfismo. L’ereditarietà permette di sviluppare soluzioni a problemi complessi in modo incrementale attraverso la definizione di nuovi oggetti in termini di oggetti precedentemente definiti. L’incapsulamento dei dati permette di nascondere lo stato interno degli oggetti. Gli oggetti incapsulati sono quegli oggetti che possono essere valutati solo utilizzando i loro metodi, invece di accedere direttamente ai loro stati interni. Per realizzare l’incapsulamento bisogna riferirsi alle parti pubbliche e private di una classe. Parti private sono gli stati interni della classe che appartengono alla classe e non possono essere acceduti direttamente dall’esterno. Parti pubbliche sono i comportamenti, i metodi, che facendo parte di una classe hanno visibilità degli attributi della stessa e quindi possono accedervi in lettura e scrittura, permettendo cosı̀ di esporre in maniera controllata lo stato interno agli altri oggetti dell’ambiente. L’identità dell’oggetto permette agli oggetti del database di essere indipendenti l’uno dall’altro. Il Polimorfismo ed il binding dinamico permettono di definire le operazioni per un oggetto e poi di condividere la specifica della cooperazione con altri oggetti. Questo permette agli utenti e/o programmatori di comporre oggetti, di fornire soluzioni senza dover riscrivere il codice comune a più classi. Un linguaggio per OODBMS si compone di una parte per la definizione dei dati ed un’altra per la manipolazione del linguaggio (DDML = odl + oql). L’uso di questo linguaggio permette di creare dati persistenti, aggiornarli, cancellarli e 6 CAPITOLO 1. PANORAMA TECNOLOGICO recuperarli. Un OODBMS ha insito un vantaggio computazionale rispetto a un database relazionale, perché evita il disadattamento (mismatch) di impedenza. Il DDML - Document Definition Markup Language - permette agli utenti di definire una base di dati, inclusa la creazione, modifica ed eliminazione di oggetti e di stabilirne le relazioni. Inoltre i linguaggi DDML vengono utilizzati per effettuare operazioni di mantenimento e di interrogazione di un database, cioè, operazioni come l’aggiornamento, l’inserimento, la modifica e l’interrogazione dei dati. Gli OODBMS presentano molti vantaggi: sono orientati agli oggetti pertanto permettono di rappresentare la realtà il modo più naturale. le operazioni definite su questi tipi di sistemi non dipendono dalla particolare applicazione di database che è in esecuzione in un dato momento. i tipi di dati trattati dai database orientati agli oggetti possono essere estesi per supportare dati complessi. derivati dall’object-oriented sono la riusabilità, la stabilità e l’affidabilità. le relazioni sono rappresentate in modo esplicito, spesso sostenendo sia l’accesso alla navigazione che l’accesso associativo alle informazioni. Questo si traduce in un miglioramento delle prestazioni di accesso ai dati rispetto al modello relazionale a scapito comunque della manutenibilità. gli utenti sono autorizzati a definire i propri metodi di accesso ai dati e come i dati saranno rappresentati e/o manipolati in maniera flessibile. Lo svantaggio maggiore degli OODBMS di dati. è che manca un modello comune La tecnologia dei database object-oriented è un matrimonio di programmazione orientata agli oggetti e tecnologie di database, la figura 1.1 mostra come questi concetti di programmazione e di database si siano uniti per offrire ciò che oggi chiamiamo i database object-oriented. Tutte queste funzionalità si uniscono sinergicamente a fornire significativi vantaggi di produttività per gli sviluppatori di applicazioni basate su database. Quando la complessità delle interrelazioni tra le informazioni all’interno del database aumenta, cosı̀ fanno anche i vantaggi che si ricavano dal rappresentare le relazioni in modo esplicito. Un altro vantaggio di rappresentare relazioni in modo esplicito è il miglioramento delle prestazioni di accesso ai dati in confronto ai database relazionali che basano tutto sul valore. Una caratteristica unica degli oggetti è che hanno un’identità che è indipendente dallo stato dell’oggetto. Per esempio, su un oggetto macchina possiamo rimodellare la macchina e cambiare il suo aspetto, il motore, la trasmissione, e le gomme in modo che appaia completamente diverso, sebbene venga comunque riconosciuto come lo stesso oggetto che avevamo inizialmente. L’Object-identità consente agli oggetti di essere condivisi su di un sistema distribuito. 1.4. ORDBMS 7 Figura 1.1: Tecnologie OODBMS Tutti questi vantaggi applicativi rendono i database object-oriented preferibili per supportare problemi di gestione delle informazioni, caratterizzati dalla necessità di gestire: un gran numero di tipi di dati diversi, un gran numero di relazioni tra gli oggetti, oggetti con comportamenti complessi. Le aree applicative dove questo tipo di complessità esiste comprendono l’ingegneria, la fabbricazione, le simulazioni, l’office automation. 1.4 ORDBMS Gli ORDBMS - Object-Relational Database Management System - sono sistemi il cui punto focale è “il tentativo di estendere i sistemi di database relazionali con le funzionalità necessarie per supportare una classe più ampia di applicazioni e, in molti modi, fornire un ponte tra i paradigmi relazionali e object-oriented”. Gli ORDBMS sono stati creati per gestire nuovi tipi di dati complessi in risposta al paradigma OODBMS, di fatto il loro sviluppo fu spinto dal maggiore utilizzo dei linguaggi di programmazione object-oriented per la gestione dei dati complessi. Il vantaggio fondamentale dei sistemi ORDBMS è permettere alle aziende di continuare a utilizzare i sistemi esistenti, senza dover fare grandi cambiamenti, 8 CAPITOLO 1. PANORAMA TECNOLOGICO proponedosi come una estensione – naturale evoluzione – dei database relazionali. Un secondo vantaggio è che permettono agli utenti e programmatori di iniziare a utilizzare sistemi orientati agli oggetti in parallelo all’utilizzo dei db relazionali. Il modello dei dati offerto dagli ORDBMS è compatibile col modello dei dati relazionali, cosı̀ da consentire la definizione di tabelle e vincoli di integrità SQL. Ad ogni modo è suggerito utilizzare un approccio diverso tramite la definizione di tipi cosı̀ da avere un maggiore riutilizzo delle strutture create col meccanismo delle gerarchie. L’uso di costruttori complessi rimarca una prima sostanziale differenza dai database relazionali classici. I tipi possono essere: tipi distinti: corrispondono ai domini di SQL. tipi strutturati: sono usati per creare le strutture delle tuple da inserire nelle tabelle. Oltre ai tipi questi dbms offrono la possibilità di scrivere delle procedure direttamente nel linguaggio applicativo di riferimento (c++, java, ecc.) in accordo alle caratteristiche degli odbms. Una relazione, utilizzando questa tecnologia, si riduce, dal punto di vista tecnico, ad una relazione unaria le cui tuple corrispondono ad oggetti. La complessità del linguaggio consente di produrre tuple con all’interno varie sottotuple, offrendo la possibilità di descrivere in maniera complessa oggetti complessi. Gli ORDBMS offrono la possibilità di riusare gli oggetti con il meccanismo delle gerarchie che possono essere di Tipo o di Tabella, in accordo a quanto avviene nel paradigma object-oriented. La tecnologia degli ORDBMS sebbene, come già detto, non rivoluzionaria ha avuto grande successo, in quanto molti dei maggiori produttori di RDBMS se ne sono interessati, favorendo cosı̀ il suo rapido sviluppo. Ad oggi i database Oracle, Microsoft SQL Server e l’IBM col suo DB2 suportano questa tecnologia. Capitolo 2 MongoDB MongoDB è un’implementazione in C++ di un DBMS document-oriented. Sul sito ufficiale di riferimento (http://www.mongodb.org) le caratteristiche chiave del sistema portano ad una rassicurante tagline: MongoDB (from “humongous”) is a scalable, high-performance, open source, document-oriented database. Nei prossimi paragrafi si scenderà nel dettaglio delle caratteristiche del sistema, grazie alle quali questo riesce a coprire il vuoto tra i sistemi chiave-valore veloci e altamente scalabili - ed i classici RDBMS - che presentano un set completo di funzionalità e ricchezza di query, a fronte di una maggiore complessità e pesantezza. 2.1 Document-oriented storage E’ possibile implementare database doc-oriented realizzando uno strato software da porre su un database ad oggetti relazionale (ORDBMS) oppure partendo da un database orientato agli oggetti (OODBMS). Nel primo caso gli oggetti prenderanno posto direttamente nel database e saranno resi disponibili attraverso query in un apposito linguaggio. MongoDB segue il secondo approccio, quello in cui si utilizzano oggetti persistenti in un linguaggio di programmazione orientato agli oggetti ed un set di API per memorizzare e recuperare gli oggetti stessi. Dal paradigma doc-oriented eredita il meccanismo di storage: non si memorizzano i dati in tabelle con campi uniformi per ogni record come nei database relazionali, ma ogni record è memorizzato come un documento (un oggetto persistente, quindi) che possiede determinate caratteristiche. Qualsiasi numero di campi con qualsiasi lunghezza può essere aggiunto al documento. I campi possono anche contenere pezzi multipli di dati. Un esempio concreto di documento contenente informazioni su di un viaggio, potrebbe essere il seguente: { ” id ” : ” rev ” : ”9 a826400d60073813c6f62508f9260e5 ” , ” 1 −1915117622 ” , 9 10 CAPITOLO 2. MONGODB ” type ” : ” destination ” : ” dates ” : ” Travel ” , ” Tokio ” , { ” from ” : ” 15/07/2010 ” , ” to ” : ” 10/08/2010 ” }, ” p a r t i c i p a n t s ” : [ ” S i l v e s t r o ” , ” Luca ” , ” Pippo ” ] } Per inquadrare subito le potenzialità di un simile approccio immaginiamo di voler aggiungere in un secondo momento, in una applicazione già in produzione su i viaggi effettuati, informazioni relative ad i mezzi di trasporto usati ed il clima incontrato. Basterebbe estendere in questo modo il documento: { ” id ” : ” rev ” : ” type ” : ” destination ” : ” dates ” : ”9 a826400d60073813c6f62508f9260e5 ” , ” 1 −1915117622 ” , ” Travel ” , ” Tokio ” , { ” from ” : ” 15/07/2010 ” , ” to ” : ” 10/08/2010 ” }, ” p a r t i c i p a n t s ” : [ ” S i l v e s t r o ” , ” Luca ” , ” Pippo ” ] , ” u s i n g ” : [ ” c a r ” , ” bus ” , ” a i r p l a n e ” ] , ” w e a t h e r s ” : [ ” sunny ” , ” c l o u d y ” ] } Normalizzazione vs Incorporamento In un modello relazionale sinonimo di qualità di un database è il livello di normalizzazione adottato per le sue tabelle (salvo poi rinunciarvi a favore di maggiori performance). Proprietà di una certa rilevanza per l’applicativo vengono quindi solitamente promosse ad Entità separate, referenziate con l’Entità originaria, in modo da non perderne semantica e contenuto informativo. Nei doc-oriented si segue un indirizzo opposto, accorpando quanto più possibile gli oggetti, creando macro-entità dal massimo contenuto informativo, che risucchiano/incorporano tutte le informazioni di cui necessitano per una determinata semantica. Collezioni e linee guida Quando un oggetto viene promosso nel mondo docoriented viene creata una collezione per tutti gli oggetti dello stesso tipo. Ci sono alcune semplici considerazioni che possono chiarire in quali caso l’incorporamento di oggetti in altri oggetti o la creazione di collezioni possa condurre ad una sensibile variazione positiva in termini di performance: gli oggetti progettati per contenere altri oggetti, incorporano questi ultimi le relazioni molti a molti sono generalmente risolte per riferimento collezioni con pochi oggetti possono non essere accorpate se l’applicazione permette un buon livello di caching gli oggetti incorporati, diversamente da quelli di primo livello nella root della collezione, difficilmente possono essere referenziati 2.2. SUPPORTO COMPLETO INDICI 11 incorporare oggetti rende difficile realizzare viste di livello più profondo di quello principale per la collezione c’è un limite di natura fisica (gli oggetti sono salvati in file) che limita le dimensioni per un singolo oggetto se l’applicazione richiede performance elevate, l’incorporamento è una soluzione efficace 2.2 Supporto completo Indici Come in tutti i DBMS che si rispettino anche ai doc-oriented è richiesta la presenza di indici. Cosı̀, in MongoDB: il campo id è indicizzato automaticamente i campi sui quali è tipico eseguire ricerche o acceduti di frequente andrebbero indicizzati i campi su cui sono definiti ordinamenti generalmente andrebbero indicizzati MongoDB fornisce strumenti in grado di suggerire su quali campi sia opportuno definire indici, dove non ve ne fossero. Vale ovviamente come regola del pollice alto privileggiare campi di collezioni con un alto rapporto letture/scritture (applicazioni read-intensive), avendo gli indici peso prestazionale nelle scritture ed esaltando le letture. Resta comunque vero che gli indici vanno utilizzati preferibilmente se il campo è realmente selettivo. Gli indici sono utilizzati per migliorare le performance delle interrogazioni del database. E’ importante pianificare che tipo di interrogazioni saranno effettuate sul sistema per scegliere il giusto indice. In MongoDB, un indice è una struttura dati che cataloga le informazioni circa i valori dei campi specificati nei documenti in una collezione. La struttura dati che realizza l’indice è utilizzata dall’ottimizzatore delle query per ordinare velocemente i documenti all’interno della collaction trattando un insieme di dati più leggero (l’indice appunto, invece che l’intera collaction). In MongoDB la struttura dati utilizzata per implementare gli indici è il B-Tree. Una volta definito un indice su uno o più campi sarà compito del sistema provvedere a mantenere aggiornato l’indice e di riflesso fornire performance maggiori sulle letture che interrogano i campi chiave. Direttamente dalla shell di Mongo è possibile definire chiavi: semplici realizzate indicando il campo di una collection come campo indice. composta realizzate indicando come campo indice un insieme di due o più campi. documento realizzate indicando come campo dell’indice un campo che contiene oggetti. In questo caso solo interrogazioni con ordinamento casuale avranno senso, mentre per interrogazioni ordinate converrà considerare chiavi composte. array realizzate indicando come campo dell’indice un campo che contiene un array. In questo caso ogni elemento dell’array sarà ordinato. 12 CAPITOLO 2. MONGODB E’ possibile inoltre definire un indice sparso su un determinato campo, cosı̀ facendo nell’indice saranno compresi solo gli oggetti che presentano il campo indicato, mentre quelli che non lo presentano verranno filtrati. Definire un indice univoco permetterà di esser sicuri che non sia possibile per due oggetti differenti memorizzare lo stesso valore per il campo definito come chiave univoca. Caratteristica peculiare di MongoDB è la possibilità di utilizzare indici geospaziali bidimensionali. Una volta definito un indice geospaziale sarà possibile interrogare la collezioni con query basate sulla posizione geospaziale del tipo trova gli N elementi più vicini alla mia posizione o criteri più specifici del tipo trovami gli N musei più vicini alla mia posizione. 2.3 Replication La replicazione è utilizzata per rimediare a malfunzionamenti ed introdurre ridondanza dei dati nella base dati, sempre a scopo di prevenzione. MongoDB realizza la replicazione in due modalità: Master-Slave solo il nodo che funge da master modifica direttamente la base dati, lo slave viene periodicamente sincronizzato con il master ed utilizzato per le letture. In questo modo in ambito distribuito si assicura una consistenza assoluta sul master ed una consistenza relativa sullo slave, nel senso che prima o poi lo slave risulterà sincronizzato con il master. Replica Sets è una elaborazione del modello Master-Slave che aggiunge il ripristino automatico dopo un malfunzionamento ed il supporto di cluster di server con membri primari (master) e secondari (slave). 2.4 Auto-Sharding Lo sharding è una tecnica utilizzata all’interno dei database per il partizionamento orizzontale. Nel partizionamento verticale - la normalizzazione - una tabella viene splittata in più tabelle dividendo i domini (campi) della tabella stessa in modo da separare ed isolare semantiche omogenee. Nel partizionamento orizzontale lo split è realizzato in modo da ottenere due o più insiemi di tuple da sistemare in due o più tabelle. Lo sharding estende il concetto di partizionamento orizzontale permettendo di avere agli shard - ovvero le partizioni ottenute dal db di partenza - di essere slegati completamente gli uni dagli altri. In particolare: ogni shard può vivere in una istanza dello schema logico totalemente separato; il server fisico del database che ospita lo shard può essere diverso da quello degli altri; il data center può essere qualsiasi, addirittura trovarsi in un altro continente. 2.4. AUTO-SHARDING 13 I vantaggi del partizionamento realizzato sulla base dati iniziale sono diversi: è ridotto il numero totale di righe di ogni tabella coinvolta; le dimensioni degli indici è ridotto, le ricerche risultano più efficienti; ogni shard può essere posizionato su hardware differente, permettendo cosı̀ di ottenere performance superiori grazie al parallelismo; la segmentazione dei dati può seguire in maniera più naturale quello del mondo reale per una migliore gestione e separazione. Un esempio su un reale utilizzo dello sharding ne può chiarire l’utilità. Tale tecnica infatti si presta particolarmente per tabelle che prevedno intrinsecamente un raggruppamento per l’ambito applicativo di interesse. Possiamo allora considerare un portale di commercio elettronico di vaste proporzioni con due mercati relativamente separati come Europa e Stati Uniti. In un contesto simile lo sharding prevede di realizzare due tabelle separate identiche strutturalemente - con i dati relativi ai prodotti destinati al mercato statunitense e quelli relitivi al mercato europero. E’ possibile addirittura prevedere che tali tabelle siano fisicamente implementate su due server distinti, geograficamente localizzati in modo da aumentare le performance - quindi probabilmente uno negli U.S.A e uno nel vecchio continente. Una soluzione del genere è auspicabile sia che vi sia una netta separazione tra i due mercati - politiche aziendali potrebbero ad esempio proibire spedizioni intercontinentali e quindi avrebbe perfettamente senso non permettere acquisti di articoli americani in Europa e viceversa - sia che sia possibile fare richieste ad un continente diverso dal proprio. La logica si complicherebbe ma i vantaggi sarebbero comunque esaltati. Immaginando infatti che le richieste per prodotti in un altro continente - o su scala mondiale - siano meno frequenti si può immaginare uno scenario nel quale server slave continentali aggiornino periodicamente un master globale che ha visione quindi completa sul reale stato del magazzino mondiale dello store. E’ chiaramente una gestione che comporterebbe un maggior carico di lavoro ed una visione non in tempo reale dello stato del sistema, ma che permetterebbe comunque di ottimizzare le operazioni più frequenti del sistema senza rinunciare alla visione - differita - globale. Auto-Sharding è il meccanismo attraverso il quale MongoDB segmenta automaticamente una collezione una volta impostata una chiave sulla quale eseguire lo sharding. La collezione viene riallocata in più collezioni strutturalmente identiche cercando di fare in modo che le dimensioni in termini di oggetti o occupazione di spazio siano bilanciate tra gli shard - le collezioni in cui è stata segmentata la collezione iniziale. Supponiamo di avere una collezione con un migliaio di oggetti al suo interno e di volere eseguire lo sharding su di un campo a della collezione iniziale. MongoDB provvederà a realizzare m collezioni shard ognuna con un numero bilanciato di oggetti. Quando sarà necessario effettuare ricerche sulla collezione iniziale MongoDB interrogherà un’apposita tabella per sapere a quali shard rivolgersi per ottenere i corrispondenti oggetti. 14 CAPITOLO 2. MONGODB 2.5 Querying Una delle più importanti caratteristiche di MongoDB è la sua capacità di supportare query dinamiche (ad hoc). I sistemi che supportano le query dinamiche non richiedono degli indici speciali per trovare i dati; gli utenti possono trovare i dati usando un qualsiasi criterio. Le query dinamiche sono caratteristiche dei database relazionali, pertanto, se si decide di migrare dati da un database relazionale verso un MongoDB si scoprirà che molte query SQL verranno trasformate facilmente in query del linguaggio document-based. Il mongodb supporta varie query-object per recuperare dati. Utilizza un pattern modellato su BSON document. MongoDB supporta una vasta gamma di selettori per i documenti. Tra le possibili query effettuabili notiamo: Selettore di campo è possibile specificare di mostrare nei risultati solo un sottoinsieme di campi. In maniera analoga a quanto avviene nella SELECT di SQL, l’unica differenza è che il campo id è sempre ritornato, anche quando non specificato. Selezione è possibile indicare criteri attraverso i quali recuperare un sottoinsieme dei documenti in una collection. In maniera uguale a quanto si fa in SQL con la WHERE. E’ possibile ovviamente utilizzare per la selezione, come in SQL: operatori condizionali (and, or, nor, in, nin, all, exists, mod, size, type, ne) espressioni regolari valori in array valori negli oggetti embedded meta operatori (not) operatore di aggregazione (group) Ordinamenti le query in MongoDB possono ritornare risultati ordinati in maniera crescente o decrescente, specificando oppurtanamente su quale campo eseguire l’ordinamento. In maniera analoga a quanto avviene con la clausola ORDER BY in SQL. Skip & Limit sono le opzioni tramite le quali effettuare la paginazione dei risultati in maniera semplice. In maniera equivalente in SQL si trovano gli stessi operatori. E’ importante sottolineare come i risultati di una query vengano gestiti. MongoDB utilizza la tecnica dei cursori, questi sono usati per recuperare iterativamente tutti i documenti ritornati dalla query eseguita. Capitolo 3 MongoDB HowTo 3.1 Installazione In questo capitolo si illustra la procedura di installazione per MongoDB e le operazioni comuni che ci si aspetta da un DBMS. 1. Download dei file all’indirizzo http://www.mongodb.org/display/DOCS/Downloads 2. Estrazione dei file in una directory qualsiasi (da questo momento tale cartella sarà indicata come install dir ) 3. Creazione della directory root per i dati del database, di default tale directory è C:\data\db 4. Lancio del demone mongod.exe dalla cartella install dir \bin Figura 3.1: Avvio demone mongod 15 16 CAPITOLO 3. MONGODB HOWTO 5. Lancio della shell di comando mongo.exe dalla cartella install dir \bin Figura 3.2: Avvio della shell mongo NOTA: nella versione a 32bit sussistono alcune limitazione in termini di dimensioni di file che incidono sulle dimensioni del db stesso. 3.1.1 Utilizzo avanzato del demone mongod E’ possibile specificare parametri al lancio del demone mongod: logging Per ridirezionare il logging del server è sufficiente indicare dove locare il file di log e come appendere i dati di log semplicemente con il comando seguente: > . / mongod −−f o r k −−l o g p a t h / v a r / l o g /mongodb . l o g −−l o g a p p e n d path db Può risultare comodo decidere esplicitamente dove salvare tutti i dati relativi a database e collezioni con il seguente comando: > . / mongod −−dbpath / v a r / l i b /mongodb/ porta E’ inoltre possibile modificare la porta di ascolto del server con il comando: > . / mongod −−p o r t 12345 3.2. GESTIONE DATABASE 3.2 17 Gestione Database La shell di mongoDB permette di interrogare i database ed il sistema attraverso semplici comandi, elencabili attraverso il comando db.help() > db . h e l p ( ) DB methods : db . addUser ( username , password [ , readOnly=f a l s e ] ) db . auth ( username , password ) db . c l o n e D a t a b a s e ( f r o m h o s t ) db . commandHelp ( name ) r e t u r n s t h e h e l p f o r t h e command db . copyDatabase ( fromdb , todb , f r o m h o s t ) db . c r e a t e C o l l e c t i o n ( name , { s i z e : . . . , capped : . . . , max : . . . } ) db . currentOp ( ) d i s p l a y s t h e c u r r e n t o p e r a t i o n i n t h e db db . dropDatabase ( ) db . e v a l ( func , a r g s ) run code s e r v e r −s i d e db . g e t C o l l e c t i o n ( cname ) same a s db [ ' cname ' ] o r db . cname db . g e t C o l l e c t i o n N a m e s ( ) db . g e t L a s t E r r o r ( ) − j u s t r e t u r n s t h e e r r msg s t r i n g db . g e t L a s t E r r o r O b j ( ) − r e t u r n f u l l s t a t u s o b j e c t db . getMongo ( ) g e t t h e s e r v e r c o n n e c t i o n o b j e c t db . getMongo ( ) . s e t S l a v e O k ( ) a l l o w t h i s c o n n e c t i o n t o r e a d from t h e nonmaster member o f a r e p l i c a p a i r db . getName ( ) db . g e t P r e v E r r o r ( ) db . g e t P r o f i l i n g L e v e l ( ) − d e p r e c a t e d db . g e t P r o f i l i n g S t a t u s ( ) − r e t u r n s i f p r o f i l i n g i s on and s l o w threshold db . g e t R e p l i c a t i o n I n f o ( ) db . g e t S i s t e r D B ( name ) g e t t h e db a t t h e same s e r v e r a s t h i s one db . i s M a s t e r ( ) c h e c k r e p l i c a primary s t a t u s db . k i l l O p ( o p i d ) k i l l s t h e c u r r e n t o p e r a t i o n i n t h e db db . listCommands ( ) l i s t s a l l t h e db commands db . p r i n t C o l l e c t i o n S t a t s ( ) db . p r i n t R e p l i c a t i o n I n f o ( ) db . p r i n t S l a v e R e p l i c a t i o n I n f o ( ) db . p r i n t S h a r d i n g S t a t u s ( ) db . removeUser ( username ) db . r e p a i r D a t a b a s e ( ) db . r e s e t E r r o r ( ) db . runCommand ( cmdObj ) run a d a t a b a s e command . i f cmdObj i s a s t r i n g , t u r n s i t i n t o { cmdObj : 1 } db . s e r v e r S t a t u s ( ) db . s e t P r o f i l i n g L e v e l ( l e v e l ,< slowms >) 0= o f f 1=s l o w 2= a l l db . s h u t d o w n S e r v e r ( ) db . s t a t s ( ) db . v e r s i o n ( ) c u r r e n t v e r s i o n o f t h e s e r v e r db . getMongo ( ) . s e t S l a v e O k ( ) a l l o w q u e r i e s on a r e p l i c a t i o n s l a v e server 18 3.2.1 CAPITOLO 3. MONGODB HOWTO Selezione del database Per poter gestire i database il primo comando da utilizzare è show dbs, in modo da avere la lista dei database disponibili per il demone in running. Grazie al comando use è possibile selezionare un database sul quale lavorare. > show dbs admin 0 . 0 7 8 1 2 5GB local ( empty ) test 0 . 0 7 8 1 2 5GB >u s e t e s t s w i t c h e d t o db t e s t > 3.2.2 Creazione del database Per creare un database in MondoDB è necessario selezionare il database che si vuole creare (mydb) tramite il comando use mydb per poi creare al suo interno una prima collezione db.createCollection(nome collezione) > u s e mydb s w i t c h e d t o db mydb > show dbs admin 0 . 0 7 8 1 2 5GB local ( empty ) test 0 . 0 7 8 1 2 5GB > db . c r e a t e C o l l e c t i o n ( ” m y c o l l e c t i o n ” ) { ” ok ” : 1 } > show dbs admin 0 . 0 7 8 1 2 5GB local ( empty ) mydb 0 . 0 7 8 1 2 5GB test 0 . 0 7 8 1 2 5GB > db . g e t C o l l e c t i o n N a m e s ( ) [ ” m y c o l l e c t i o n ” , ” system . i n d e x e s ” ] > 3.2.3 Eliminazione del database Per eliminare un database in MondoDB è necessario selezionare il database che si vuole creare (mydb) tramite il comando use mydb per poi utilizzare il comando db.dropDatabase() > show dbs admin 0 . 0 7 8 1 2 5GB local ( empty ) mydb 0 . 0 7 8 1 2 5GB test 0 . 0 7 8 1 2 5GB > db . dropDatabase ( ) { ” dropped ” : ”mydb” , ” ok ” : 1 } > show dbs 3.2. GESTIONE DATABASE admin local test > 0 . 0 7 8 1 2 5GB ( empty ) 0 . 0 7 8 1 2 5GB 19 20 CAPITOLO 3. MONGODB HOWTO 3.3 Gestione Utenti 3.3.1 Creazione Utente Per creare un utente in un database è necessario selezionare il database per poi utilizzare il comando db.addUser(nome, password [, readOnly=false]) > db . addUser ( ” Cavani ” , ” matador ” , t r u e ) { ” u s e r ” : ” Cavani ” , ” readOnly ” : t r u e , ”pwd” : ” c 4 c 6 f 5 d 2 e 8 a e 9 5 a 8 5 a c 0 4 f f 9 8 0 c 9 9 0 5 5 ” } Il campo readOnly se settato su true specifica che l’utente avrà solo permessi di lettura sul database. Utenti Globali per associare un utente a tutti i db è sufficiente aggiungere tale utente al db admin 3.3.2 Modifica Utente Per modificare un utente è sufficiente utilizzare nuovamente il comando db.addUser(nome, password [, readOnly=false]) > db . addUser ( ” L a v e z z i ” , ” pocho ” , t r u e ) { ” user ” : ” Lavezzi ” , ” readOnly ” : t r u e , ”pwd” : ” 70 f 7 b d 6 b 6 8 e 8 c 4 1 f e 6 1 2 c 6 8 b e 8 6 5 b 9 1 2 ” } > db . system . u s e r s . f i n d ( ) { ” i d ” : O b j e c t I d ( ” 4 d 0 e 4 b 6 c a 7 3 8 0 0 0 0 0 0 0 0 4 c 8 a ” ) , ” u s e r ” : ” Cavani ” , ” readOnly ” : t r u e , ”pwd” : ” c 4 c 6 f 5 d 2 e 8 a e 9 5 a 8 5 a c 0 4 f f 9 8 0 c 9 9 0 5 5 ” } { ” i d ” : ObjectId ( ”4 d0e4bfba738000000004c8b ” ) , ” user ” : ” Lavezzi ” , ” readOnly ” : t r u e , ”pwd” : ” 70 f 7 b d 6 b 6 8 e 8 c 4 1 f e 6 1 2 c 6 8 b e 8 6 5 b 9 1 2 ” } > db . addUser ( ” L a v e z z i ” , ” g o l e a d o r ” ) { ” i d ” : ObjectId ( ”4 d0e4bfba738000000004c8b ” ) , ” user ” : ” Lavezzi ” , ” readOnly ” : f a l s e , ”pwd” : ” c 1 c 4 6 b f f e c 9 1 7 a 3 0 c 4 d 7 d 2 3 b 6 7 6 e a 6 4 8 ” } > Da osservare come il sisteama riporti l’id del record utente in oggetto e come la password venga per sicurezza salvata con un hash. 3.3.3 Eliminazione Utente Per eliminare un utente è possibile utilizzare il comando db.removeUser(nome) 3.3. GESTIONE UTENTI > > [ > { { > > { 21 db . system . u s e r . f i n d ( ) db . g e t C o l l e c t i o n N a m e s ( ) ” system . i n d e x e s ” , ” system . u s e r s ” ] db . system . u s e r s . f i n d ( ) ” i d ” : O b j e c t I d ( ” 4 d 0 d e 3 c b 5 b 1 8 0 0 0 0 0 0 0 0 3 a f c ” ) , ” u s e r ” : ” admin ” , ” readOnly ” : f a l s e , ”pwd” : ” c 5 3 2 b 4 c 1 9 6 5 a d d a e 1 c 9 3 4 5 e 6 2 8 2 6 f b 5 2 ” } ” i d ” : O b j e c t I d ( ” 4 d 0 d e a 2 b 5 b 1 8 0 0 0 0 0 0 0 0 3 a f f ” ) , ” u s e r ” : ” admin1 ” , ” readOnly ” : t r u e , ”pwd” : ” 5 a d a e 9 a 7 b 7 6 8 f d a 4 f d d 2 4 3 0 f 8 f 2 3 d 7 7 7 ” } db . removeUser ( ” admin1 ” ) db . system . u s e r s . f i n d ( ) ” i d ” : O b j e c t I d ( ” 4 d 0 d e 3 c b 5 b 1 8 0 0 0 0 0 0 0 0 3 a f c ” ) , ” u s e r ” : ” admin ” , ” readOnly ” : f a l s e , ”pwd” : ” c 5 3 2 b 4 c 1 9 6 5 a d d a e 1 c 9 3 4 5 e 6 2 8 2 6 f b 5 2 ” } 3.3.4 Autenticazione Utente MongoDB prevede due modalità di accesso: senza e con autenticazione. Chiaramente senza autenticazione si dà la possibilità a chiunque di accedere indiscriminatamente alle informazioni. E’ quindi buona norma prevedere l’autenticazione per gli utenti, in modo da scongiurare accessi non autorizzati. Ci si può autenticare con username e password di un utente in un particolare database, e l’utente stesso con il login ha attribuiti dei privilegi che possono essere di sola lettura o di lettura-scrittura, a seconda del profilo dell’utente associato all’username e password inseriti. Il database admin è speciale, in quanto, un utente con determinati privilegi nel db admin è un utente con quei privilegi per ogni db, inoltre ha la possibilità di eseguire delle operazioni di amministrazione che altrimenti non potrebbe eseguire. Per abilitare questi controlli di sicurezza bisogna lanciare il demone mongod con l’ opzione –auth, per farlo si deve aver creato precedentemente un utente nel database admin di amministrazione. Per effettuare il login di amministrazione si deve selezionare il db admin e digitare il comando db.auth(username, password) nella consolle mongo. Una volta fatto questo si potrà accedere ad ogni altro db come se vi avessimo fatto il login. % L a n c i o i l demone mongod E : \ mongodb−win32−i 3 8 6 − 1 . 7 . 3 \ mongo\ bin>mongod −−auth ................................................................. connecting to : t e s t > show dbs Mon Dec 27 1 4 : 0 5 : 2 2 uncaught e x c e p t i o n : l i s t D a t a b a s e s f a i l e d : { ” a s s e r t i o n ” : ” u n a u t h o r i z e d db : admin l o c k t y p e : −1 c l i e n t :127.0.0.1” , ” assertionCode ” : 10057 , ” errmsg ” : ”db a s s e r t i o n f a i l u r e ” , ” ok ” : 0 } % non p o s s o f a r e i l l o g i n i n t e s t > db . auth ( ” admin ” , ” a d m i n i s t r a t o r ” ) 0 > show dbs Mon Dec 27 1 4 : 0 6 : 1 8 uncaught e x c e p t i o n : l i s t D a t a b a s e s f a i l e d : { 22 CAPITOLO 3. MONGODB HOWTO ” a s s e r t i o n ” : ” u n a u t h o r i z e d db : admin l o c k t y p e : −1 c l i e n t :127.0.0.1” , ” assertionCode ” : 10057 , ” errmsg ” : ”db a s s e r t i o n f a i l u r e ” , ” ok ” : 0 } % r i e s c o a l o g g a r m i n e l dbs admin > u s e admin s w i t c h e d t o db admin > db . auth ( ” admin ” , ” a d m i n i s t r a t o r ” ) 1 > show dbs admin 0 . 0 7 8 1 2 5GB local ( empty ) mydb 0 . 0 7 8 1 2 5GB mydb1 0 . 0 7 8 1 2 5GB test 0 . 0 7 8 1 2 5GB %una v o l t a l o g g a t o da a m m i n i s t r a t o r e vado e vedo c i o che v o g l i o > u s e mydb s w i t c h e d t o db mydb > db . g e t C o l l e c t i o n N a m e s ( ) [ ” system . i n d e x e s ” , ” system . u s e r s ” ] > Se si desidera creare un amministratore non dell’intero sistema ma solo di un particolare db basta creare un utente al suo interno. Le credenziali di logging di questo utente gli daranno dei privilegi solo all’interno del db stesso. connecting to : t e s t > u s e mydb s w i t c h e d t o db mydb > db . auth ( ” Localadmin ” , ” a m m i n i s t r a t o r e ” ) 1 > db . g e t C o l l e c t i o n N a m e s ( ) [ ” system . i n d e x e s ” , ” system . u s e r s ” ] % l a m m i n i s t r a t o r e l o c a l e non ha v i s i b i l i t a ' d e g l i a l t r i dbs > show dbs Mon Dec 27 1 4 : 2 7 : 5 3 uncaught e x c e p t i o n : l i s t D a t a b a s e s f a i l e d : { ” a s s e r t i o n ” : ” u n a u t h o r i z e d db : admin l o c k t y p e : −1 c l i e n t :127.0.0.1” , ” assertionCode ” : 10057 , ” errmsg ” : ”db a s s e r t i o n f a i l u r e ” , ” ok ” : 0 } % anche s e c i puo e n t r a r e non ne ha v i s i b i l i t a ' d e i c o n t e n u t i > u s e mydb1 s w i t c h e d t o db mydb1 > db . g e t C o l l e c t i o n N a m e s ( ) Mon Dec 27 1 4 : 2 5 : 5 4 uncaught e x c e p t i o n : e r r o r : { ” $ e r r ” : ” u n a u t h o r i z e d db : mydb1 l o c k t y p e : −1 c l i e n t : 1 2 7 . 0 . 0 . 1 ” , ” code ” : 10057 } > 3.3. GESTIONE UTENTI 23 24 3.4 CAPITOLO 3. MONGODB HOWTO Gestione Collezioni Come per i database è disponibile un helper specifico per le collection, utilizzando il comando db.nome collection.help() > db . m y c o l l e c t i o n . h e l p ( ) DBCollection help db . m y c o l l e c t i o n . f i n d ( ) . h e l p ( ) − show DBCursor h e l p db . m y c o l l e c t i o n . count ( ) db . m y c o l l e c t i o n . d a t a S i z e ( ) db . m y c o l l e c t i o n . d i s t i n c t ( key ) − eg . db . m y c o l l e c t i o n . d i s t i n c t ( ' x' ) db . m y c o l l e c t i o n . drop ( ) drop t h e c o l l e c t i o n db . m y c o l l e c t i o n . d r o p I n d e x ( name ) db . m y c o l l e c t i o n . d r o p I n d e x e s ( ) db . m y c o l l e c t i o n . e n s u r e I n d e x ( k e y p a t t e r n , o p t i o n s ) − o p t i o n s s h o u l d be an o b j e c t with t h e s e p o s s i b l e f i e l d s : name , unique , dropDups db . m y c o l l e c t i o n . r e I n d e x ( ) db . m y c o l l e c t i o n . f i n d ( [ query ] , [ f i e l d s ] ) − f i r s t p a r a m e t e r i s an o p t i o n a l query f i l t e r . s e c o n d p a r a m e t e r i s o p t i o n a l s e t o f f i e l d s t o r e t u r n . e . g . db . m y c o l l e c t i o n . f i n d ( { x : 77 } , { name : 1 , x : 1 } ) db . m y c o l l e c t i o n . f i n d ( . . . ) . count ( ) db . m y c o l l e c t i o n . f i n d ( . . . ) . l i m i t ( n ) db . m y c o l l e c t i o n . f i n d ( . . . ) . s k i p ( n ) db . m y c o l l e c t i o n . f i n d ( . . . ) . s o r t ( . . . ) db . m y c o l l e c t i o n . findOne ( [ query ] ) db . m y c o l l e c t i o n . findAndModify ( { update : . . . , remove : b o o l [ , query : { } , s o r t : { } , ' new ' : f a l s e ] } ) db . m y c o l l e c t i o n . getDB ( ) g e t DB o b j e c t a s s o c i a t e d with c o l l e c t i o n db . m y c o l l e c t i o n . g e t I n d e x e s ( ) db . m y c o l l e c t i o n . group ( { key : . . . , i n i t i a l : . . . , r e d u c e : . . . [ , cond : . . . ] } ) db . m y c o l l e c t i o n . mapReduce ( mapFunction , r e d u c e F u n c t i o n , < o p t i o n a l params> ) db . m y c o l l e c t i o n . remove ( query ) db . m y c o l l e c t i o n . r e n a m e C o l l e c t i o n ( newName , <dropTarget> ) renames t h e c o l l e c t i o n . db . m y c o l l e c t i o n . runCommand ( name , <o p t i o n s > ) r u n s a db command with t h e g i v e n name where t h e f i r s t param i s t h e c o l l e c t i o n name db . m y c o l l e c t i o n . s a v e ( o b j ) db . m y c o l l e c t i o n . s t a t s ( ) db . m y c o l l e c t i o n . s t o r a g e S i z e ( ) − i n c l u d e s f r e e s p a c e a l l o c a t e d t o this collection db . m y c o l l e c t i o n . t o t a l I n d e x S i z e ( ) − s i z e i n b y t e s o f a l l t h e indexes db . m y c o l l e c t i o n . t o t a l S i z e ( ) − s t o r a g e a l l o c a t e d f o r a l l data and indexes db . m y c o l l e c t i o n . update ( query , o b j e c t [ , u p s e r t b o o l , m u l t i b o o l ] ) db . m y c o l l e c t i o n . v a l i d a t e ( ) − SLOW db . m y c o l l e c t i o n . g e t S h a r d V e r s i o n ( ) − o n l y f o r u s e with s h a r d i n g 3.4. GESTIONE COLLEZIONI 25 NOTA: è possibile utilizzare un qualsiasi nome di collezione, anche di non create, ottenendo ugualmente un help su di una generica collezione, completo di tutti i comandi di default eseguibili sulle collezioni. 3.4.1 Creazione Collezione Per creare una nuova collezione in un database è sufficiente selezionare il database di interesse ed invocare il metodo db.createCollaction(nome collezione) > u s e mydb s w i t c h e d t o db mydb > db . g e t C o l l e c t i o n N a m e s ( ) [ ] > db . c r e a t e C o l l e c t i o n ( ” C a l c i a t o r i ” ) { ” ok ” : 1 } > db . g e t C o l l e c t i o n N a m e s ( ) [ ” C a l c i a t o r i ” , ” system . i n d e x e s ” ] > 3.4.2 Creazione Oggetto Per creare un oggetto si può procedere in diversi modi: In modo esplicito si crea l’oggetto - usando la sintassi JSON - e poi per renderlo persistente nel database lo si inserisce all’interno di una collection, pertanto l’oggetto appena creato sarà visibile a tutti solo all’atto dell’inserimento nella collection. Un oggetto creato resta utilizzabile a livello della sessione di connessione finchè l’utente resta connesso, pertanto se lo si vuole è modificabile e per eliminarlo lo si deve cancellare esplicitamente. L’ oggetto resta utilizzabile anche se si cambia db come vedremo nella sezione Eliminazione Oggetto. > c a l c i a t o r e = {nome : ”Marco” , cognome : ” M a t e r a z z i ” , p r e z z o : ” 10000 ” } { ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” } > db . C a l c i a t o r i . i n s e r t ( c a l c i a t o r e ) > db . C a l c i a t o r i . f i n d ( ) { ” i d ” : O b j e c t I d ( ” 4 d 0 e 5 3 5 c a 7 3 8 0 0 0 0 0 0 0 0 4 c 8 c ” ) , ”nome” : , ” cognome ” : ” L a v e z z i ” , ” a l i a s ” : ” Pocho ” } { ” i d ” : O b j e c t I d ( ” 4 d 0e5 41b a73 800 000 000 4c8 d ” ) , ”nome” : ” cognome ” : ” Cavani ” , ” a l i a s ” : ” Matador ” , ” bomber ” { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 2 9 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 3 ” ) , ”nome” : cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” } ” Ezequiel ” ” Edinson ” , : ” true ” } ”Marco” , ” > db . C a l c i a t o r i . s a v e ( c a l c i a t o r e ) > db . C a l c i a t o r i . f i n d ( ) { ” i d ” : O b j e c t I d ( ” 4 d 0 e 5 3 5 c a 7 3 8 0 0 0 0 0 0 0 0 4 c 8 c ” ) , ”nome” : ” E z e q u i e l ” , ” cognome ” : ” L a v e z z i ” , ” a l i a s ” : ” Pocho ” } { ” i d ” : O b j e c t I d ( ” 4 d 0e5 41b a73 800 000 000 4c8 d ” ) , ”nome” : ” Edinson ” , ” cognome ” : ” Cavani ” , ” a l i a s ” : ” Matador ” , ” bomber ” : ” t r u e ” } 26 CAPITOLO 3. MONGODB HOWTO { ” i d ” : ObjectId ( ”4 d148829610f000000001b33 ” ) cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” { ” i d ” : ObjectId ( ”4 d148842610f000000001b34 ” ) cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” , ”nome” : ”Marco” , ” } , ”nome” : ”Marco” , ” } In modo implicito si può creare un oggetto direttamente all’interno di una collection, in questo caso l’oggetto non ha una vita propria ma la sua esistenza è legata alla collection in cui lo si crea. > db . C a l c i a t o r i . i n s e r t ( { nome : ” Pippo ” , cognome : ” I n z a g h i ” , r u o l o : ” attaccante ” }) > db . C a l c i a t o r i . f i n d ( ) { ” i d ” : O b j e c t I d ( ” 4 d 0 e 5 3 5 c a 7 3 8 0 0 0 0 0 0 0 0 4 c 8 c ” ) , ”nome” : ” E z e q u i e l ” , ” cognome ” : ” L a v e z z i ” , ” a l i a s ” : ” Pocho ” } { ” i d ” : O b j e c t I d ( ” 4 d 0e5 41b a73 800 000 000 4c8 d ” ) , ”nome” : ” Edinson ” , ” cognome ” : ” Cavani ” , ” a l i a s ” : ” Matador ” , ” bomber ” : ” t r u e ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 2 9 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 3 ” ) , ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 4 2 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 4 ” ) , ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 8 9 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 5 ” ) , ”nome” : ” Pippo ” , ” cognome ” : ” I n z a g h i ” , ” r u o l o ” : ” a t t a c c a n t e ” } > db . C a l c i a t o r i . s a v e ( { nome : ” Pippo ” , cognome : ” I n z a g h i ” , r u o l o : ” attaccante ” }) > db . C a l c i a t o r i . f i n d ( ) { ” i d ” : O b j e c t I d ( ” 4 d 0 e 5 3 5 c a 7 3 8 0 0 0 0 0 0 0 0 4 c 8 c ” ) , ”nome” : ” E z e q u i e l ” , ” cognome ” : ” L a v e z z i ” , ” a l i a s ” : ” Pocho ” } { ” i d ” : O b j e c t I d ( ” 4 d 0e5 41b a73 800 000 000 4c8 d ” ) , ”nome” : ” Edinson ” , ” cognome ” : ” Cavani ” , ” a l i a s ” : ” Matador ” , ” bomber ” : ” t r u e ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 2 9 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 3 ” ) , ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 4 2 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 4 ” ) , ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 8 9 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 5 ” ) , ”nome” : ” Pippo ” , ” cognome ” : ” I n z a g h i ” , ” r u o l o ” : ” a t t a c c a n t e ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 9 c 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 6 ” ) , ”nome” : ” Pippo ” , ” cognome ” : ” I n z a g h i ” , ” r u o l o ” : ” a t t a c c a n t e ” } > 3.4.3 Modifica Oggetto Un oggetto può esistere a livello di sessione o all’interno di una collection: Nel primo caso l’oggetto esiste a livello di sessione e le modifiche avvengono tramite la ridefinizione di tutti gli attributi dell’oggetto stesso. > calciatore { ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” , 3.4. GESTIONE COLLEZIONI 27 ” i d ” : ObjectId ( ”4 d148842610f000000001b34 ” ) } > c a l c i a t o r e = {nome : ”Marco” , cognome : ” M a t e r a z z i ” , p r e z z o : ” 1000000 ” } { ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 1000000 ” } > c a l c i a t o r e = { p r e z z o : ” 100 ” } { ” p r e z z o ” : ” 100 ” } > calciatore { ” p r e z z o ” : ” 100 ” } Nel secondo caso si accede ad un oggetto contenuto in una collection, esistente indipendentemente dalla sessione, questo si può modificare col comando: update(query, obj [, upsert bool, multi bool]) { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 4 2 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 4 ” ) , ”nome” : ” Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 8 9 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 5 ” ) , ”nome” : ” Pippo ” , ” cognome ” : ” I n z a g h i ” , ” r u o l o ” : ” a t t a c c a n t e ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 9 c 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 6 ” ) , ”nome” : ” Pippo ” , ” cognome ” : ” I n z a g h i ” , ” r u o l o ” : ” a t t a c c a n t e ” } > db . C a l c i a t o r i . update ( { nome : ” Pippo ” } , { $ s e t : { cognome : ” Esempio ” } } ) > db . C a l c i a t o r i . f i n d ( ) { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 4 2 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 4 ” ) , ”nome” : ” Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 10000 ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 8 9 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 5 ” ) , ”nome” : ” Pippo ” , ” cognome ” : ” Esempio ” , ” r u o l o ” : ” a t t a c c a n t e ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 9 c 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 6 ” ) , ”nome” : ” Pippo ” , ” cognome ” : ” I n z a g h i ” , ” r u o l o ” : ” a t t a c c a n t e ” } > Il mongodb prevede varie opzioni di modifica (3.1) per il comando update: Opzione $addToSet $set $unset $inc $push $pushAll $pull $pullAll $pop $rename Azione aggiunge il valore all’array solo se questo non è già presente setta il valore di un determinato campo elimina un campo incrementa di un particolare valore partendo dall’ammontare iniziale aggiunge un valore ad un array aggiunge più valori ad un array rimuove un valore ad un array rimuove più valori da un array rimuove l’ultimo valore dall’array rinomina il campo con un nuovo nome Tabella 3.1: Tabella delle opzioni di modifica 28 CAPITOLO 3. MONGODB HOWTO Inoltre si possono effettuare modifiche semplici con il comando save() che permette di modificare un oggetto usando l’opzione upsert, se l’oggetto esiste lo modifica se non esiste lo inserisce nella collection. 3.4.4 Eliminazione Oggetto Per quanto riguarda la cancellazione va distinto il caso in cui l’oggetto sia interno o meno ad una collection: Nel caso in cui un oggetto sia definito all’interno di una sessione per venire usato piu volte, si può ottenere la cancellazione dell’oggetto in due modi: 1. direttamente: si cancella l’oggetto usando direttamente la delete. > c a l c i a t o r e = {nome : ”Marco” , cognome : ” M a t e r a z z i ” , p r e z z o : ” 1000000 ” } { ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 1000000 ” } > calciatore { ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” : ” 1000000 ” } > delete calciatore true > calciatore F r i Dec 24 1 3 : 1 1 : 4 6 R e f e r e n c e E r r o r : c a l c i a t o r e i s not defined ( s h e l l ) :0 > 2. indirettamente: l’oggetto viene eliminato automaticamente alla chiusura della sessione. Nell’esempio è mostrato come l’oggetto persista grazie alla sessione, anche su database diversi, essendo un oggetto allocato globalmente nella sessione. Una volta chiusa la sessione l’oggetto non risulta più disponibile. > c a l c i a t o r e = {nome : ”Marco” , cognome : ” M a t e r a z z i ” , p r e z z o : ” 1000000 ” } { ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” 1000000 ” } > calciatore { ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” 1000000 ” } > use t e s t s w i t c h e d t o db t e s t > calciatore { ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” 1000000 ” } . . To mydb . . . > calciatore { ”nome” : ”Marco” , ” cognome ” : ” M a t e r a z z i ” , ” p r e z z o ” 1000000 ” } > exit bye E : \ mongodb−win32−i 3 8 6 − 1 . 7 . 3 \ mongo\ bin>mongo : ” : ” : ” : ” 3.4. GESTIONE COLLEZIONI MongoDB s h e l l v e r s i o n : 1 . 7 . 3 c o n n e c t i n g t o : mydb > calciatore F r i Dec 24 1 3 : 1 6 : 5 6 R e f e r e n c e E r r o r : c a l c i a t o r e defined ( s h e l l ) :0 > 29 i s not Nel secondo caso si deve cancellare un oggetto inserito in una collection, per realizzare questa operazione si procede usando la remove(query ). Il metodo in base alla query passata, effettuerà una scansione della collection, eliminando tutti gli oggetti che rispettino le condizioni della query. > db . C a l c i a t o r i . f i n d ( ) { ” i d ” : O b j e c t I d ( ” 4 d 0 e 5 3 5 c a 7 3 8 0 0 0 0 0 0 0 0 4 c 8 c ” ) , ”nome” E z e q u i e l ” , ” cognome ” : ” L a v e z z i ” , ” a l i a s ” : ” Pocho ” } { ” i d ” : O b j e c t I d ( ” 4 d 0e5 41b a73 800 000 000 4c8 d ” ) , ”nome” Edinson ” , ” cognome ” : ” Esempio ” , ” a l i a s ” : ” Matador ” , ” bomber ” : ” t r u e ” } { ” i d ” : O b j e c t I d ( ” 4 d 1 4 8 8 8 9 6 1 0 f 0 0 0 0 0 0 0 0 1 b 3 5 ” ) , ”nome” Pippo ” , ” cognome ” : ”E sempio ” , ” r u o l o ” : ” a t t a c c a n t e ” } > db . C a l c i a t o r i . remove ( { cognome : ” Esempio ” } ) > db . C a l c i a t o r i . f i n d ( ) { ” i d ” : O b j e c t I d ( ” 4 d 0 e 5 3 5 c a 7 3 8 0 0 0 0 0 0 0 0 4 c 8 c ” ) , ”nome” E z e q u i e l ” , ” cognome ” : ” L a v e z z i ” , ” a l i a s ” : ” Pocho ” } 3.4.5 : ” : ” : ” : ” Eliminazione Collezione L’eliminazione di una collection comporta l’eliminazione di tutti gli oggetti interni alla collection stessa, si effettua tramite il comando drop(). > db . c o l l P r o v a . i n s e r t ( { nome : ” prova ” } ) > db . c o l l P r o v a . p r o v a i n t e r n a 1 . i n s e r t ( { nome : ” prova ” } ) > db . g e t C o l l e c t i o n N a m e s ( ) [ ” Calciatori ” , ” collProva ” , ” collProva . provainterna1 ” , ” system . i n d e x e s ” ] > db . c o l l P r o v a . drop ( ) true > db . g e t C o l l e c t i o n N a m e s ( ) [ ” Calciatori ” , ” collProva . provainterna1 ” , ” system . i n d e x e s ” ] > 30 CAPITOLO 3. MONGODB HOWTO Capitolo 4 Conclusioni Il MongoDB è giunto ormai alla versione 1.6.5. Nel corso degli anni ha rafforzato le sue potenzialità, raggiungendo oggi una certa stabilità e diversi punti di forza che lo caratterizzano: l’auto-sharding e la possibilità di scalare in maniera orizzontale; l’alta disponibilità dai dati; il ripristino automatico dai guasti. Nel corso degli anni le esigenze applicative relative alle basi di dati si sono spostate dalla semplice catalogazione di file di testo, a delicate transazioni bancarie per poi arrivare oggi ad avere utilizzatori finali che non solo utilizzano l’applicazione, ma dinamicamente, ogni giorno, la ridisegnano a proprio uso e consumo. E’ proprio questa forte spinta all’user-centric del web 2.0 che ha fatto esplodere il fenomeno di database meno tradizionali e nati proprio per le nuove generazioni di applicazioni. Oggi siamo molto vicini a quella che si profila essere la nuova era del web, la sua terza generazione, con tutta l’attenzione posta sulla semantica. In un tale scenario le applicazioni che vedranno sempre più la luce saranno applicazioni con un forte indice di evoluzione, in cui non solo nuove tipologie di relazioni saranno all’ordine del giorno - se non dell’ora - ma persino il più piccolo frammento di dato dovrà gravitare attorno ad oggetti flessibili ed in grado di modellare realtà sempre diverse. In tale ottica ecco venire alla luce soluzioni innovative come i documentoriented di cui MongoDB è un rappresentante di spicco, grazie anche a particoli punti di forza sui quali può contare: un driver client in ogni linguaggio: protocolli socket nativi per le interfacce client/server (non REST); uso di file memory mapped per la memorizzazione dei dati; memorizzazione collection-oriented (le collezione sono archiviati in modo contiguo); consente l’update-in-place (non MVCC); è scritto in C++. 31 32 CAPITOLO 4. CONCLUSIONI Tutto questo accompagnato da scelte architetturali ed una implementazione che ne garantisce performance superiori ad altri sistemi analoghi ed un set completo di funzionalità che lo pongono nel panorama attuale come una scelta sicuramente vincente, se ciò di cui si ha bisogno è una piattaforma sufficientemente stabile ed al tempo stesso attenta a seguire strettamente i trend evolutivi del mercato delle applicazioni. Data questa sua propensione ad essere un sistema malleabile ed al tempo stesso performante, il MongoDB potrebbe essere una buona scelta per supportare problemi come: 1. problemi in cui si vogliono avere delle prestazioni elevate come possono essere quelli per la memorizzazione dei profili utenti di un sito web; 2. problemi in cui è richiesto un tasso di aggiornamento alto come avviene, ad esempio, nell’aggiornamento dei contatori per l’analisi in tempo reale dei siti web; 3. problemi in cui il labeling delle risorse è fondamentale e diversificato. Capitolo 5 Appendice 5.A Sintassi JSON JSON (JavaScript Object Notation) è un semplice formato per lo scambio di dati. Per le persone è facile da leggere e scrivere, mentre per le macchine risulta facile da generare e analizzarne la sintassi. I tipi supportati sono: booleani (true e false); interi, reali, virgola mobile; stringhe racchiuse da doppi apici ( ); array (sequenze ordinate di valori, separati da virgole e racchiusi in parentesi quadre [ ] ); array associativi (sequenze coppie chiave-valore separate da virgole racchiuse in parentesi graffe); null. E’ possibile combinare tali tipi di dati in due strutture fondamentali: un insieme di coppie nome/valore. In diversi linguaggi, questo è realizzato come un oggetto, un record, uno struct, un dizionario, una tabella hash, un elenco di chiavi o un array associativo. un elenco ordinato di valori. Nella maggior parte dei linguaggi questo si realizza con un array, un vettore, un elenco o una sequenza. Oggetto è una serie non ordinata di nomi/valori. Un oggetto inizia con { (parentesi graffa sinistra) e finisce con } (parentesi graffa destra). Ogni nome è seguito da : (due punti) e la coppia di nome/valore sono separata da , (virgola). v a r c a r = { ” e n g i n e ” : ” d i e s e l ” , ” w h e e l s ” : 4} Array è una raccolta ordinata di valori. Un array comincia con [ (parentesi quadra sinistra) e finisce con ] (parentesi quadra destra). I valori sono separati da , (virgola). 33 34 CAPITOLO 5. APPENDICE v a r f r u i t s = [ ” a p p l e ” , ” o r a n g e ” , ” banana ” ] Valore può essere una stringa tra virgolette, o un numero, o vero o falso o nullo, o un oggetto o un array. Queste strutture possono essere annidate. Stringa è una raccolta di zero o più caratteri Unicode, tra virgolette; per le sequenze di escape utilizza la barra rovesciata. Un singolo carattere è rappresentato come una stringa di caratteri di lunghezza uno. Una stringa è molto simile ad una stringa C o Java. Strutture composte è possibile combinare tutti i tipi di dati in strutture complesse. var car = { ” engine ” : ” d i e s e l ” , ” wheels ” : 4 , ” o p t i o n a l s ” : [ ” abs ” , ” e p s ” , ” a i r b a g ” : { ” d r i v e r ” : t r u e , ” s i d e ” : t r u e , ” baby ” : f a l s e } ] } 5.B. MIGRARE DA SQL A MONGODB 5.B 35 Migrare da SQL a MongoDB Nella tabella 5.1 si mostra cosa offre mongo rispetto ad un database relazionale come mysql. Modello dei Dati Tipi di Dato Supporto Files Schema di partizionamento orizzontale Replicazione Memorizzazione Oggetti (Righe) Metodi di Query Indici secondari Atomicità Interfacce Scritto in Controllo di Concorrenza Indici Geospaziali Modello di Consistenza Distribuito MongoDB Document-Oriented (BSON) string, int, double, boolean, date, bytearray, object, array, others Si Auto-Sharding(v1.6) MySQL Relazionale tipi numerici, tipi date and time, tipi string (character) Master-slave (e replica sets) Basata sulle Collection Master-slave Basata sulle tabelle Linguaggio di query object-based Si Documenti Singoli Driver Nativi ed add-on tipo Rest C++ modifica sul posto SQL Si Si, avanzata Driver Nativi Si (da giugno 2010 il sistema di coordinate è cartesiano, le coordinate sferiche sono in corso d’opera) Consistenza rigida, sono disponibili le letture consistenti da siti secondari Supportati parzialmente ? ? C++ ? Consistenza rigida, sono disponibili le letture consistenti da siti secondari Tabella 5.1: Tabella tecnica SQL MongoDB La tabella 5.2 riporta alcune query Sql con il rispettivo equivalente in MongoDB, in cui è possibile notare l’uso degli oggetti JSON per le query. 36 CAPITOLO 5. APPENDICE SQL Statement CREATE TABLE USERS (a Number, b Number) INSERT INTO USERS VALUES(1, 1) SELECT a, b FROM users SELECT * FROM users SELECT * FROM users WHERE age = 33 SELECT a,b FROM users WHERE age = 33 SELECT * FROM users WHERE age = 33 ORDER BY name SELECT * FROM users WHERE age>33 SELECT * FROM users WHERE age<33 SELECT * FROM users WHERE name LIKE “%Joe%” SELECT * FROM users WHERE name LIKE “Joe%” SELECT * FROM users WHERE age>33 AND age<=40 SELECT * FROM users ORDER BY name DESC CREATE INDEX myindexname ON users(name) CREATE INDEX myindexname ON users(name, ts DESC) SELECT * FROM users WHERE a=1 and b = ‘q’ SELECT * FROM users LIMIT 10 SKIP 20 SELECT * FROM users WHERE a=1 or b=2 SELECT * FROM users LIMIT 1 EXPLAIN SELECT * FROM users WHERE z=3 SELECT DISTINCT last name FROM users SELECT COUNT(*) FROM users SELECT COUNT(*) FROM users WHERE AGE > 30 SELECT COUNT(AGE) FROM users UPDATE users SET a = 1 WHERE b = ‘q’ UPDATE users SET a = a+2 WHERE b = ‘q’ DELETE FROM users WHERE z = ‘abc’ Mongo Query Language Statement implicito; può essere fatto direttamente db.users.insert({“a”: 1, “b”: 1}) db.users.find({}, {“a”: 1, “b”: 1}) db.users.find() db.users.find({“age”: 33}) db.users.find({“age”: 33}, {“a”: 1, “b”: 1}) db.users.find({“age”: 33}).sort({“name”: 1}) db.users.find({“age”: {$gt: 33}}) db.users.find({“age”: {$lt: 33}}) db.users.find({“name”: /Joe/}) db.users.find({“name”: /ˆJoe/}) db.users.find({“age”: {$gt: 33, $lte: 40}}) db.users.find().sort({“name”: -1}) db.users.ensureIndex({“name”: 1}) db.users.ensureIndex({“name”:1, “ts”:1}) db.users.find({“a”: 1, “b”: ‘q’}) db.users.find().limit(10).skip(20) db.users.find( { $or : [ {“a”: 1 } , {“b”: 2 } ] } ) db.users.findOne() db.users.find({“z”: 3}).explain() db.users.distinct(“last name”) db.users.count() db.users.find({“age”:{$gt:30}}).count() db.users.find( {“age”:{$exists: true}}).count() db.users.update( {“b”: ‘q’}, {$set: {“a”: 1}}, false, true) db.users.update( {“b”: ’q’}, {$inc:{“a”: 2}}, false, true) db.users.remove({“z”: ‘abc’}); Tabella 5.2: Tabella comparativa SQL-MongoDB Bibliografia [1] P.Atzeni ed Altri. Basi di Dati. Architetture e linee di evoluzione. McGraw Hill [2] Wikipedia. Document-oriented Database. [http://en.wikipedia.org/wiki/Documentoriented database] [3] Documentazione MongoDB [http://www.mongodb.org/display/DOCS] [4] Dropping ACID with MongoDB [http://www.slideshare.net/kchodorow/droppingacid-with-mongodb] [5] Wikipedia. MongoDB. [http://en.wikipedia.org/wiki/MongoDB] 37