DEV Community

Apruzzese Francesco
Apruzzese Francesco

Posted on Edited on

TinyDB per Python - Quando JSON si crede un database

Premessa noiosa

Durante la realizzazione di un progetto per un cliente (Python + GTK, giusto per curiosità) mi sono ritrovato davanti alla situazione di dover salvare dei dati collezionati durante l'uso dell'applicativo che sarebbero poi stati inviati ad un sistema ERP esterno.
Essendo i dati comunque pochi, legati strettamente alla singola macchina e non eccessivamente interconnessi tra di loro, mi sembrava eccessivo utilizzare un database (sì, anche sqlite mi sembrava "troppo"). Dovendo però prevedere alcune situazioni di distaster più o meno complesse, anche il mantenimento delle informazioni in memoria era un via non proprio percorribile. Ho cercato così una strada che mi permettesse di salvare le informazioni in un file mantenendo però la praticità delle query e di ciò che un database sa offrire. La mia ricerca mi ha portato a scoprire TinyDB.

tinydb_logo

La parte Superquark

TinyDB è una libreria per Python che può essere vista come la versione dei programmatori con davvero pochissime esigenze di MongoDB. Grazie all'uso di dati strutturati JSON, TinyDB permette di avere un database simulato all'interno di un comune file di testo con annesse tabelle, campi, valori e query di ricerca e gestione.

Punti di forza

  • Possibilità di gestire i dati come dizionari essendo gli stessi salvati e caricati dal formato JSON
  • 100% codice Python senza bisogno di librerie esterne (né pip né di sistema)
  • Uso di simil-query per interrogare e manipolare i dati
  • Accesso ai dati organizzati in tabelle
  • Il database è un file di testo. Lo copi, lo invii, lo apri e lo leggi.
  • Può essere esteso per coprire ogni tipo di esigenza (creare ad esempio base di dati customizzate)

Debolezze

  • Non permette di avere dati relazionati
  • Non gestisce gli indici autoincrementali
  • Le performance calano al crescere del file
  • Non gestisce le scritture concorrenti

Codice divertente

Tralascio la parte dove si parla di installazioni così possiamo passare all'analisi di un po' di codice (finalmente!!!).

Come prima cosa importiamo il minimo indispensabile per aprire il database

>>> from tinydb import TinyDB
>>> db = TinyDB('/tmp/test.tdb')
Enter fullscreen mode Exit fullscreen mode

Abbiamo appena istanziato il nostro dabase generando il file necessario nel nostro sistema. Qualora il file non dovesse esistere, verrà generato con la prima chiamata utile. Recandoci nella cartella /tmp possiamo trovare test.tdb (il nome e l'estensione sono a discrezione di chi scrive il codice) che conterrà quanto segue

{"_default": {}}
Enter fullscreen mode Exit fullscreen mode

_default è la tabella base in cui verranno collocati tuttii record non associati ad una precisa tabella. Facciamo un esempio.

>>> db.insert({'name': 'Phil', 'age': 45})
1
>>> db.insert({'name': 'Logan', 'age': 56})
2
Enter fullscreen mode Exit fullscreen mode

Il contenuto del nostro file ora sarà

{"_default": {"1": {"age": 45, "name": "Phil"}, "2": {"age": 56, "name": "Logan"}}}
Enter fullscreen mode Exit fullscreen mode

Proviamo ora a vedere come gestire le tabelle

>>> superhero = db.table('superhero')
Enter fullscreen mode Exit fullscreen mode

Ora nel nostro file sarà presente che la chiave che indica la nuova tabella

{"_default": {
    "1": {"age": 45, "name": "Phil"},
    "2": {"age": 56, "name": "Logan"}}, 
"superhero": {}}
Enter fullscreen mode Exit fullscreen mode

A questo punto sarà possibile usare la tabella per eseguire le operazioni

>>> superhero.insert({'name': 'Batman', 'is_cool': True})
1
>>> superhero.insert({'name': 'Superman', 'is_cool': True})
2
>>> superhero.insert({'name': 'Zuppaman', 'is_cool': False})
3
Enter fullscreen mode Exit fullscreen mode

È possibile ottenere tutti i valori di una tabella (o di _default interrogandlo direttamente l'istanza del db) mediante la funzione all()

>>> superhero.all()
[{u'is_cool': True, u'name': u'Batman'}, {u'is_cool': True, u'name': u'Superman'}, {u'is_cool': False, u'name': u'Zuppaman'}]
Enter fullscreen mode Exit fullscreen mode

Le ricerche possono essere effettuate in diversi modi. Guardiamone alcuni.

Uso di ricerche semplici

>>> from tinidb import Query

>>> # Ricerca semplice
>>> superhero.search(Query().name == 'Superman')
[{u'is_cool': True, u'name': u'Superman'}]
>>> superhero.search(Query()['name'] == 'Superman')
[{u'is_cool': True, u'name': u'Superman'}]

>>> # OR tra due clausole
>>> superhero.search((Query().name == 'Superman') | (Query().name == 'Zuppaman'))
[{u'is_cool': True, u'name': u'Superman'}, {u'is_cool': False, u'name': u'Zuppaman'}]

>>> # Uso delle espressioni regolari
>>> superhero.search(Query().name.matches('Bat[a-z]'))
[{u'is_cool': True, u'name': u'Batman'}]
Enter fullscreen mode Exit fullscreen mode

Clausole where

>>> from tinydb import where
>>> superhero.search(where('name') == 'Superman')
[{u'is_cool': True, u'name': u'Superman'}]
Enter fullscreen mode Exit fullscreen mode

L'uso delle ricerche ci permette di gestire i dati. Con esse infatti è possibile eseguire, ad esempio, l'aggiornamento delle informazioni

>>> # Upserting dei dati con clausola
>>> superhero.upsert({'name': 'Zuppaman', 'is_cool': True}, Query().name == 'Zuppaman')
Enter fullscreen mode Exit fullscreen mode

Conclusioni

Ovviamente un solo post non basterebbe per snocciolare le potenzialità di una libreria. Per questo vi rimando alla guida introduttiva e a quella più avanzata che spiegano davvero bene cosa è possibile fare e come farlo.

Supporto

Buy Me A Coffee

Top comments (0)