Sur mon dernier projet, j'avais besoin de stocker un peu de données. Les solutions que je connaissais déjà ne me convenaient pas. Je n'avais ni envie de mettre en place une base de donnée SQL ni envie de m'embêter avec des fichiers JSON.
Il me fallait quelque chose entre les deux.
<blockquote>A database optimised for your happiness.
</blockquote>J'ai cherché un peu et j'ai découvert TinyDB qui est une minuscule base de données document oriented.
Ça existe depuis des années et ça continue d'être mis à jour régulièrement. C'est parfait pour les petits projets personnels. L'API est super simple et amusante à utiliser !
C'est un outil que tu devrais ajouter dans ta besace de développeur chevronné, je te le conseille.
Dans cet article, je te présente l'outil et je te montre les fonctionnalités de base comme l'ajout, la suppression, la mise à jour et la recherche.
Ah oui, TinyDB est open source, cela veut dire que tu peux y contribuer sur GIthub si jamais ça t'intéresse ! 👍
Les avantagesformat_paragraph
- Écrit en Python pur
- Aucune dépendances
- Document Oriented
- Compatible Python2 et Python3
- Facile à utiliser, API très propre
- Légère (~2000 lignes de codes, pas plus)
- Extensible pour coller à vos besoins
→ Si tu as besoin d'une base de données simple avec une API propre qui fonctionne bien sans beaucoup de configurations, TinyDB pourrait être le bon choix pour toi.
Les inconvénientsformat_paragraph
- Impossible de créer des index vu que c'est stocké en JSON
- Impossible de gérer les relations entre les tables pour les mêmes raisons
- Pas de garantie ACID (donc évite les opérations 'critiques' comme des paiements)
- Faibles performances
→ Si tu as besoin de fonctionnalités avancées ou de hautes performances, TinyDB n'est pas la bonne base de données pour toi - pense à utiliser des bases de données plus classiques comme SQLite3 qui est fournie dans la librairie standard de Python.
Comment on l'utilise ?format_paragraph
Tout d'abord, il faut que tu l'installes, ça paraît évident. Pour ça, rien de compliqué, on passe par pip
comme d'habitude :
pip install tinydb
Ensuite, on importe la librairie et on définit notre base de données :
from tinydb import TinyDB, Query, where
db = TinyDB('db.json')
Sans rentrer dans les détails :
TinyDB
- Représente ta base de donnéesQuery
- Permet d'interroger ta base de donnéeswhere
- Permet d'affiner tes critères de recherche
Si tu exécutes ce code, cela va juste créer un fichier db.json
vide.
On va ensuite créer une table. Comme c'est bientôt l'été, j'ai envie de partir sur des fruits :
from tinydb import TinyDB, Query
db = TinyDB('db.json')
fruits = db.table('fruits')
Si tu ne crées pas de table, TinyDB le fait pour toi automatiquement et crée une table _default
.
En faisant ça, tes données sont accessibles à n'importe quel moment et n'importe où dans ton programme sans que tu aies besoin de te reconnecter à ta base de données au préalable !
Personnellement, je trouve ça vraiment pratique.
Tout est prêt, on peut commencer à peupler notre table fruits
:
J'utilise pprint
plutôt que la fonction print
de base histoire que ce soit plus simple à lire.
from tinydb import TinyDB, Query
from pprint import pprint
db = TinyDB('db.json')
fruits = db.table('fruits')
fruits.insert({'type': 'fraise', 'quantite': 4})
fruits.insert({'type': 'orange', 'quantite': 1})
fruits.insert({'type': 'banane', 'quantite': 7})
pprint(fruits.all())
#[{'quantite': 4, 'type': 'fraise'},
#{'quantite': 1, 'type': 'orange'},
#{'quantite': 7, 'type': 'banane'}]
Et si on regarde du côté de notre fichier db.json
:
{"fruits": {"1": {"type": "fraise", "quantite": 4}, "2": {"type": "orange", "quantite": 1}, "3": {"type": "banane", "quantite": 7}}}
Tu peux remarquer que chaque entrée est automatiquement associée à un doc_id
unique qui s'incrémente automatiquement à chaque fois que tu insères une nouvelle valeur 🙂
Tu peux aussi itérer sur le items
de ta table avec une boucle for
classique :
for fruit in fruits:
pprint(fruit)
#[{'quantite': 4, 'type': 'fraise'},
#{'quantite': 1, 'type': 'orange'},
#{'quantite': 7, 'type': 'banane'}]
Et évidemment, tu peux aussi rechercher un élément en particulier, de plusieurs manières :
# SYNTAXE LONGUE
Fruit = Query()
fraise = fruits.search(Fruit.type == 'fraise')
pprint(fraise)
# [{'quantite': 4, 'type': 'fraise'}]
# SYNTAXE COURTE
fraise = fruits.search(where('type') == 'fraise')
pprint(fraise)
# [{'quantite': 4, 'type': 'fraise'}]
# VIA SON DOCUMENT ID
fraise = fruits.get(doc_id=1)
pprint(fraise)
# [{'quantite': 4, 'type': 'fraise'}]
Tu peux combiner à cela des opérateurs logiques et des opérateurs de comparaison pour affiner tes requêtes.
pprint(fruits.search((Fruit.quantite > 1) & (Fruit.quantite < 20)))
# [{'quantite': 4, 'type': 'fraise'}, {'quantite': 7, 'type': 'banane'}]
Une fois que tu as compris comment tout ça fonctionne, tu peux l'appliquer à tous les types d'opérations :
# METTRE À JOUR UN ITEM
fruits.update({'quantite': 8}, Fruit.type == 'fraise')
# SUPPRIMER UN ITEM
fruits.remove(where('type') == 'orange')
Si tu n'aimes pas ces fruits, tu peux faire du ménage comme ça :
fruits.truncate()
# {"fruits": {}}
Ou carrément supprimer tout ce qu'il y a dans ta base de données :
db.purge()
# []
Je pense que ces opérations de base couvriront 90% de tes besoins !
Si tu en veux plus, n'hésite pas à consulter la documentation officielle.
Tu pourrais par exemple stocker tes données directement en mémoire ou dans le cache plutôt que dans un fichier JSON.