Tutoriel sur MongoDB
1. Objectif
Un tout petit turoriel rapide pour découvrir MongoDB
et l’utiliser sur notre service movie
en REST. La base MongoDB du tutoriel va être deployée dans un conteneur Docker. Le fichier docker-compose.yml
contient le nécessaire le deployer.
Il faut :
-
cloner/télécharger le repo de code https://github.com/IMTA-FIL/UE-AD-A1-TUTO-MONGO
-
installer l’extension vscode
database client
-
installer Docker desktop (si ce n’est pas déjà fait) et exécuter
docker compose up
à la racine du repo -
créer un environnement virtuel Python et installer le contenu du fichier
requirements.txt
-
python3 -m venv venv
-
source venv/bin/activate
-
pip3 install -r requirements.txt
2. Se connecter à MongoDB
2.1. Mongo express
Pour vérifier que tout fonctionne bien, commencez par vous connecter sur votre navigateur à l’interface Mongo Express
aussi déployée dans un conteneur : http://localhost:8081
Mongo Express a déjà été configuré pour se connecter à la base mongo dans l’autre conteneur, vous pouvez regarder le fichier docker-compose.yml
2.2. Database client vscode
Si vous utilisez vscode, vous pouvez aller dans l’extension database
puis vous connecter à la base Mongo.
-
sélectionner la bon type de base
-
indiquer 127.0.0.1 (localhost) et laisser le port par défaut
-
indiquer le bon utilisateur et mot de passe (voir dans
docker-compose.yml
)
Vous pouvez ensuite faire des requêtes dans l’interface.
3. Utilisation de pymongo
Nous allons maintenant utiliser directement la base Mongo dans nos programmes Python. Pour cela la librairie `pymongo`a été installée dans les requirements.
Il faut d’abord importer pymongo
, ainsi que bson
pour pouvoir passer des formats pymongo
vers json
.
from pymongo import MongoClient
from bson.json_util import dumps
Nous allons maintenant nous connecter à la base de données dans le code Python directement.
client = MongoClient("mongodb://root:example@localhost:27017/")
On voit ici qu’on créée un client Mongo and se connectant à localhost
sur le port 27017
et en utilisant le bon login et password.
Nous allons maintenant nous connecter à la base de données movies
(qui sera créée si elle n’existe pas) et à la collection (équivalent à une table) du même nom (qui sera aussi créée si elle n’existe pas). C’est à partir de la collection que nous pouvons ensuite faire des requêtes. Ici nous faisons une insertion de données avec la fonction insert_many
et nous lui donnons directement le tableau de films récupéré du fichier json
.
db = client["movies"]
collection = db["movies"]
collection.insert_many(movies)
Vérifiez dans Mongo Express et dans vscode database que les données ont bien été ajoutées.
4. Modification des points d’entrée
4.1. Find
Nous allons dans un premier temps modifier la route GET /moviesbytitle
.
@app.route("/moviesbytitle", methods=['GET'])
def get_movie_bytitle():
movie = {}
if request.args:
req = request.args
movie = collection.find_one({"title": str(req["title"])})
res = make_response(dumps(movie),200)
return res
return make_response(jsonify({"error":"movie title not found"}),500)
Ici, au lieu de parcourir les films à la main dans le tableau movies
nous allons chercher les données dans la base Mongo. Pour cela nous utilisons la fonction find_one
qui consiste à chercher une entrée correspondante à la requête dans la collection movies
. Notre requête est
{"title": str(req["title"])}
Cela signifie que nous cherchons une entrée (un film) dont le title
est str(req['title'])
. Rappelons ici que req
contient les arguments de la requête HTTP dans ce cas, à savoir le titre d’un film. Notons aussi qu’il est nécessaire de caster le paramètre explicitement en string pour un bon fonctionnement.
On voit ensuite que nous n’utilisons plus la fonction jsonify
qui permet de sérialiser du json dans la réponse HTTP. A la place nous utilisons la fonction dumps
issue du from bson.json_util import dumps
. Cette fonction permet de transformer le format de sortie de la requête Mongo en json
.
Testez ce point d’entrée modifié avec Insomnia
! Que remarquez-vous ?
4.2. Find avancé
Nous allons maintenant ajouter une route permettant de filtrer les films par notes.
@app.route("/movies/minrate/<rate>", methods=['GET'])
def get_movies_minrate(rate):
mylist = list(collection.find({"rating": {"$gt": float(rate)}}))
res = make_response(dumps(mylist),200)
return res
Cette route prend en paramètre de chemin une note et retourne tous les films dont la note est strictement supérieure à celle donnée. Pour cela, nous faisons une requête find
paramètrée par {"$gt": float(rate)}
. Le $gt
signifie "greater than".
Testez ce point d’entrée avec Insomnia !
4.3. Update
Enfin, nous allons modifier la route permettant de changer la note d’un film.
@app.route("/movies/<movieid>/<rate>", methods=['PUT'])
def update_movie_rating(movieid, rate):
myquery = { "id": movieid }
newvalues = { "$set": { "rating": float(rate) } }
collection.update_one(myquery, newvalues)
res = make_response(jsonify({"message":"rate updated"}),200)
return res
Nous utilison la fonction update_one
de pymongo
pour faire une requête de mise à jour.
La requête est :
myquery = { "id": movieid }
Elle permet de trouver le film font l’ID est donné en paramètre.
La modification à apporter est spécifiée par
newvalues = { "$set": { "rating": float(rate) } }
Cela indique que nous allons attribuer la valeur float(rate)
à la clé rating
du film trouvé.
Finalement, nous appelons donc
collection.update_one(myquery, newvalues)
pour effectuer l’update.
vérifiez que la modification a bien été faite en base.