Faculté Polydisciplinaire - Safi Filières : IIA & SD / Semestre : 6
Module : Big Data et NoSQL
TP9 : Le NoSQL avec MongoDB — CRUD et requêtes sur
documents
Partie 1. Présentation et contexte
Voir l'énoncé du TP pour la présentation du contexte et la structure du dataset.
Partie 2. Mise en place — Corrigé
Q1. Affichez la liste des bases de données. La base hopital y figure-t-elle ?
show dbs
→ La base hopital doit apparaître avec sa taille après import.
Q2. Sélectionnez la base hopital et listez les collections qu'elle contient.
use hopital
show collections
→ Résultat attendu : patients, medecins, medicaments.
Q3. Combien de documents contient chacune des trois collections ?
[Link]() // 50
[Link]() // 25
[Link]() // 28
Q4. Affichez un document complet de chaque collection (avec findOne()). Notez les principales
différences de structure.
[Link]()
[Link]()
[Link]()
→ patients contient des tableaux d'objets imbriqués (consultations, prescriptions...), medecins est
plat, medicaments est plat avec quelques tableaux simples.
1/10
Faculté Polydisciplinaire - Safi Filières : IIA & SD / Semestre : 6
Q5. Comparez les champs présents dans deux patients différents. Tous les patients ont-ils
exactement les mêmes champs ? Justifiez.
// Vérifier deux patients : tous n'ont pas les mêmes champs
[Link]({ _id: "PAT001" })
[Link]({ _id: "PAT002" })
// Combien de patients ont un email ?
[Link]({ email: { $exists: true } })
→ Réponse: NON, tous les patients n'ont pas les mêmes champs.
Certains ont email, profession, mutuelle, allergies, tabagisme... d'autres non.
C'est la flexibilité du schéma MongoDB : chaque document peut avoir une structure différente au
sein d'une même collection.
Partie 3. Requêtes — Corrigé
3.1 — Création (Create)
Q6. Insérez un nouveau patient avec les champs suivants :
• _id = "PAT999",
• nom = "Tazi",
• prenom = "Khalid",
• sexe = "M",
• age = 35,
• ville = "Safi" (dans [Link]),
• aucune consultation.
[Link]({
_id: "PAT999",
nom: "Tazi",
prenom: "Khalid",
sexe: "M",
age: 35,
adresse: { ville: "Safi" }
// on peut ajouter => consultations: []
})
2/10
Faculté Polydisciplinaire - Safi Filières : IIA & SD / Semestre : 6
Q7. Insérez en une seule commande deux nouveaux médicaments :
• MDC999 — Doliprane 500mg, classe Antalgique, forme comprimé, prix 25.50 ;
• MDC998 — Spasfon, classe Antispasmodique, forme comprimé, prix 35.00.
[Link]([
{
_id: "MDC999",
nom: "Doliprane 500mg",
classe_therapeutique: "Antalgique",
forme: "comprimé",
prix_mad: 25.50
},
{
_id: "MDC998",
nom: "Spasfon",
classe_therapeutique: "Antispasmodique",
forme: "comprimé",
prix_mad: 35.00
}
])
3.2 — Lecture (Read)
Q8. Affichez tous les patients de sexe féminin.
[Link]({ sexe: "F" })
Q9. Affichez tous les patients dont l'âge est strictement supérieur à 60 ans.
[Link]({ age: { $gt: 60 } })
Q10. Affichez tous les patients ayant le groupe sanguin O+ ET résidant à Casablanca.
[Link]({
groupe_sanguin: "O+",
"[Link]": "Casablanca"
})
→ L'AND est implicite quand on liste plusieurs champs dans le même filtre. La notation pointée
"[Link]" permet de filtrer sur un champ d'un sous-document.
3/10
Faculté Polydisciplinaire - Safi Filières : IIA & SD / Semestre : 6
Solution 2 :
[Link]({
$and: [
{ groupe_sanguin: "O+" },
{ "[Link]": "Casablanca" }
]
})
3.3 — Mise à jour (Update)
Q11. Modifiez l'email du patient PAT001 pour le mettre à jour vers
"[Link]@[Link]".
[Link](
{ _id: "PAT001" },
{ $set: { email: "[Link]@[Link]" } }
)
Q12. Pour tous les patients résidant à Casablanca, ajoutez un nouveau champ secteur =
"urbain".
[Link](
{ "[Link]": "Casablanca" },
{ $set: { secteur: "urbain" } }
)
Q13. Incrémentez l’âge du patient PAT002 de 1.
[Link](
{ _id: "PAT002" },
{ $inc: { age: 1 } }
)
Q14. Supprimez le champ profession du patient PAT001.
[Link](
{ _id: "PAT001" },
{ $unset: { profession: "" } }
)
→ La valeur passée à $unset (ici "") n'a aucune importance, seul compte le nom du champ.
4/10
Faculté Polydisciplinaire - Safi Filières : IIA & SD / Semestre : 6
3.4 — Suppression (Delete)
Q15. Supprimez le patient de test créé en Q6 (PAT999).
[Link]({ _id: "PAT999" })
Q16. Supprimez les deux médicaments fictifs ajoutés en Q7 (MDC999 et MDC998).
[Link]({
_id: { $in: ["MDC999", "MDC998"] }
})
Solution 2 :
[Link]({
$or: [
{ _id: "MDC999" },
{ _id: "MDC998" }
]
})
3.5 — Opérateurs
Q17. Affichez les patients dont l'âge est compris entre 30 et 50 ans (inclus).
[Link]({ age: { $gte: 30, $lte: 50 } })
Solution 2 : cette solution est-elle correcte ?
[Link]({
age: { $gte: 30 },
age: { $lte: 50 }
})
Cette requête est incorrecte, car dans un objet JavaScript/MongoDB, deux clés identiques au même
niveau ne doivent pas être utilisées. En pratique, seule la dernière condition sur age sera prise en
compte.
Solution 2 correcte:
[Link]({
$and: [
{ age: { $gte: 30 } },
{ age: { $lte: 50 } }
]
})
5/10
Faculté Polydisciplinaire - Safi Filières : IIA & SD / Semestre : 6
Q18. Affichez les patients dont la mutuelle est CNSS ou CNOPS (utilisez $in).
[Link]({ mutuelle: { $in: ["CNSS", "CNOPS"] } })
Q19. Affichez les médecins de spécialité Cardiologue ou Endocrinologue, dont le tarif de
consultation est inférieur ou égal à 400 MAD.
[Link]({
specialite: { $in: ["Cardiologue", "Endocrinologue"] },
tarif_consultation_mad: { $lte: 400 }
})
Solution 2 :
[Link]({
$or: [
{ specialite: "Cardiologue" },
{ specialite: "Endocrinologue" }
],
tarif_consultation_mad: { $lte: 400 }
})
Solution 3 :
[Link]({
$and: [
{
$or: [
{ specialite: "Cardiologue" },
{ specialite: "Endocrinologue" }
]
},
{
tarif_consultation_mad: { $lte: 400 }
}
]
})
Q20. Affichez les patients qui n'ont pas de mutuelle (champ absent).
[Link]({ mutuelle: { $exists: false } })
→ Attention : { mutuelle: null } ne signifie pas uniquement que le champ vaut null.
En MongoDB, cette requête peut aussi retourner les documents où le champ mutuelle est absent.
Pour chercher uniquement les documents où le champ est absent, on utilise :
[Link]({ mutuelle: { $exists: false } })
6/10
Faculté Polydisciplinaire - Safi Filières : IIA & SD / Semestre : 6
3.6 — Projection et tri
Q21. Affichez uniquement le nom, prénom et la ville des patients de Marrakech. Excluez le
_id.
[Link](
{ "[Link]": "Marrakech" },
{ nom: 1, prenom: 1, "[Link]": 1, _id: 0 }
)
Q22. Affichez les 5 médecins les plus expérimentés (champ experience_annees décroissant).
[Link]()
.sort({ experience_annees: -1 })
.limit(5)
Q23. Affichez les médicaments triés par classe thérapeutique (ordre alphabétique), puis par
prix croissant à l'intérieur d'une classe.
[Link]()
.sort({ classe_therapeutique: 1, prix_mad: 1 })
3.7 — Documents imbriqués
Q24. Affichez tous les patients résidant dans la région "Marrakech-Safi".
[Link]({ "[Link]": "Marrakech-Safi" })
Q25. Affichez les patients dont au moins une consultation a pour diagnostic "gastrite".
[Link]({ "[Link]": "gastrite" })
→ Quand on utilise la notation pointée sur un champ qui est un tableau d'objets, MongoDB
cherche automatiquement dans tous les éléments du tableau.
Q26. Affichez les patients dont au moins une consultation a une tension systolique supérieure
à 150.
[Link]({ "[Link]": { $gt: 150 } })
7/10
Faculté Polydisciplinaire - Safi Filières : IIA & SD / Semestre : 6
3.8 — Tableaux
Q27. Affichez les patients allergiques à la pénicilline.
[Link]({ allergies: "pénicilline" })
→ Pour rechercher une valeur DANS un tableau, on peut écrire directement allergies:
"pénicilline" comme si c'était une valeur simple — MongoDB cherche dans tous les éléments du
tableau.
Q28. Affichez les patients allergiques à la fois aux arachides et au pollen.
[Link]({ allergies: { $all: ["arachides", "pollen"] } })
Q29. Affichez les patients ayant exactement 3 allergies.
[Link]({ allergies: { $size: 3 } })
8/10
Faculté Polydisciplinaire - Safi Filières : IIA & SD / Semestre : 6
Q30. Trouvez les patients ayant une consultation à la fois courte (duree_minutes < 20) ET avec
le diagnostic "gastrite".
[Link]({
consultations: {
$elemMatch: {
duree_minutes: { $lt: 20 },
diagnostic: "gastrite"
}
}
})
→ L’utilisation de $elemMatch est nécessaire ici car on veut que les deux conditions (durée < 20
ET diagnostic = "gastrite") soient vraies pour le MÊME élément du tableau consultations, pas
seulement présentes quelque part dans deux consultations différentes.
3.9 — Expressions régulières
Q31. Affichez les patients dont le nom commence par "El".
[Link]({ nom: /^El/ })
// ou : [Link]({ nom: { $regex: "^El" } })
Q32. Affichez les patients dont l'email se termine par "@[Link]".
[Link]({ email: /@email\.ma$/ })
→ Le point doit être échappé (\.) car en regex il signifie « n'importe quel caractère ».
Q33. Affichez les médicaments dont le nom contient "mg" (insensible à la casse).
[Link]({ nom: { $regex: "mg", $options: "i" } })
// ou : [Link]({ nom: /mg/i })
9/10
Faculté Polydisciplinaire - Safi Filières : IIA & SD / Semestre : 6
3.10 — Mise à jour des documents imbriqués
Q34. Ajoutez une nouvelle consultation au patient PAT001 (utilisez $push) avec :
• date : 2024-12-01
• medecin_id : MED001
• motif : "contrôle annuel"
• diagnostic : "bon état général"
• duree_minutes : 30
[Link](
{ _id: "PAT001" },
{
$push: {
consultations: {
date: ISODate("2024-12-01"),
medecin_id: "MED001",
motif: "contrôle annuel",
diagnostic: "bon état général",
duree_minutes: 30
}
}
}
)
Q35. Retirez l'allergie "pollen" du patient PAT002 (utilisez $pull).
[Link](
{ _id: "PAT002" },
{ $pull: { allergies: "pollen" } }
)
Q36. Modifiez le code postal de l'adresse du patient PAT001 pour le mettre à "46100".
[Link](
{ _id: "PAT001" },
{ $set: { "adresse.code_postal": "46100" } }
)
→ Pour modifier un sous-champ, on utilise la notation pointée entre guillemets dans la clé du
$set. Sans guillemets, ça ne fonctionne pas.
10/10