Documents de cours 2020-2021 - FX Jollois
NB : Pour réaliser ce TP chez vous, vous devez avoir installé le serveur Mongo, ainsi que Compass et le Shell. Les instructions sont disponibles sur cette page.
JSON
Nous allons ici créer une premi!ère base de données, que l’on nommera test
, contenant une seule collection pour le moment, nommée essais
.
admin
, config
et local
test
restaurants
test
à gauche (et la collection restaurants
lorsque vous cliquez sur la petite flèche à droite de test
)Lorsque vous cliquez sur la collection, dans la base, vous voyez le détail de son contenu. Pour le moment, notre collection restaurants
est vide. Il n’y a donc rien. Il est possible d’importer des documents directement.
Nous allons importer maintenant les données dans notre collection ainsi créée. Vous devez avoir téléchargé le fichier restaurants.json
Une fois téléchargé, suivez la procédure suivante pour l’ajouter dans Mongo :
restaurants
pour voir le contenu de la collection (vide donc pour le moment)Votre première base est maitenant créée avec une collection de 25359 restaurants donc.
Nous allons maintenant vérifier que l’opération s’est bien déroulé et qu’on peut accéder à ces données dans le terminal Mongo.
show dbs
pour afficher les bases de données existantes
test
, taper la commande use test
show collections
pour voir les collections dans ces bases
db.restaurants.count()
Vous devriez donc avoir un résultat comme ci-dessous.
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
test 0.004GB
> use test
switched to db test
> show collections
restaurants
> db.restaurants.count()
25359
Mongo utilise le langage JavaScript
pour la programmation dans le shell, avec un ensemble de méthodes permettant la gestion de la base et des données (ce qui nous concerne peu), mais aussi bien évidemment pour la recherche d’information.
Nous avons donc déjà vu comment obtenir le nombre de documents présents dans une collection, avec la fonction count()
réalisé sur l’objet db.nom_collection
(nom_collection
étant donc à remplacer par le nom de la collection qui nous intéresse). Ceci est donc équivalent à COUNT(*)
en SQL.
Il est aussi possible de se restreindre à certains documents, en réalisant donc une restriction. Pour cela, Mongo utilise un formalisme particulier. Nous allons indiquer les critères de recherche dans un objet (on dit aussi littéral) JSON
. Par exemple, si l’on souhaite avoir le nombres de restaurants de Brooklyn, nous allons exécuter la commande suivante :
> db.restaurants.count({ borough: "Brooklyn" })
6086
Nous verrons par la suite comment mettre plusieurs critères de recherche. Le formalisme est le même que dans les fonctions de recherche findOne()
et find()
que nous allons voir par la suite.
La première demande est souvent de recherche un ou plusieurs documents. Comme les documents n’ont pas de structure définies en amont, il existe une fonction (findOne()
) permettant de renvoyer le premier document. Cela permet donc de visualiser un exemple de documents.
db.restaurants.findOne()
Noter la structure du document :
_id
(clé primaire interne toujours présente), borough
, cuisine
, name
et restaurant_id
address
), contenant des champs simples (building
, street
et zipcode
) et un tableau à 2 valeurs coord
)grades
(de 5 éléments ici - la taille n’est pas la même pour chaque restaurant)
date
, grade
et score
)score
: nombre d’infractions sanitairesgrade
: sorte de note du restaurant en fonction du score (A si peu, B si plus, C si encore plus)Pour récupérer tous les documents, il faut utiliser la fonction find()
. Puisqu’il y a beaucoup de résultats, et qu’ils en sont pas tous affichables, seulement 20 sont affichés. Pour avoir les 20 suivants, vous pouvez taper it
(pour iterate). Noter que l’affichage est moins lisible (pas de passage à la ligne, ni de tabulation).
db.restaurants.find()
On peut aussi chercher le premier document respectant un critère (par exemple, situé à Brooklyn). Ce sera le premier paramètre de la fonction. Nous réalisons donc ici une restriction sur un critère simple.
db.restaurants.findOne({borough: "Brooklyn"})
On peut combiner les critères pour avoir le premier restaurant de Brooklyn, proposant de la cuisine française par exemple. Ici, les critères sont mis dans le littéral passé en paramètre, et l’outil effectue un ET entre les deux.
db.restaurants.findOne({borough: "Brooklyn", cuisine: "French"})
Les critères ici sont définis sur des champs simples. Si on veut faire une recherche sur un littéral (par exemple, on veut le premier restaurant sur “Franklin Street”), il faut procéder comme ci-dessous. Attention, il faut bien mettre les “” pour un champ intégré dans un autre (comme "address.street"
ici).
db.restaurants.findOne({"address.street": "Franklin Street"})
On peut aussi chercher dans un tableau. Par exemple, on veut avoir le premier restaurant ayant eu un score de 0 (aucune infraction sanitaire lors de l’inspection donc). Noter qu’il renvoie tous les scores.
db.restaurants.findOne({"grades.score": 0})
Ici, nous avons à chaque fois récupéré le document en entier. Mais il est parfois utile de ne récupérer que certains éléments (et donc de faire une projection). Pour cela, nous allons passer en paramètre un deuxième littéral, indiquant les champs que l’on souhaite garder (1
) ou ne pas garder (0
). Par exemple, nous ne voulons que le nom et le quartier. Noter ici que pour ne pas faire de restriction, il faut mettre un littéral vide ({}
).
db.restaurants.findOne({}, { name: 1, borough: 1 })
Noter que l’identifiant _id
est présent par défaut. Pour ne pas l’avoir, il faut l’indiquer précisemment. C’est la seule façon de mélanger un choix d’attributs à afficher (1
) et un attribut à ne pas afficher (0
).
db.restaurants.findOne({}, { _id: 0, name: 1, borough: 1 })
On peut aussi afficher que certains éléments des champs complexes (littéral ou tableau). Par exemple, on souhaite n’avoir que la rue du restaurant en plus, ainsi que la liste des grades obtenus.
db.restaurants.findOne(
{},
{
_id: 0, name: 1, borough: 1,
"address.street": 1, "grades.grade": 1
}
)
Si au contraire, on ne veut pas afficher certains éléments, on peut aussi utiliser ce formalisme. Ici, on n’affiche pas l’adresse et les visites.
db.restaurants.findOne({}, {address: 0, grades: 0})
Malheureusement, il n’est pas possible d’utiliser les opérateurs classiques pour effectuer des restrictions plus complexes que l’égalité stricte. Par exemple, pour comparer avec une valeur (infériorité ou supérioté), nous devons utiliser des opérateurs spécifiques ($lt
: less than, $lte
: less than or equal, $gt
: greater than, $gte
: greater than or equal, $ne
: note equal). Par exemple, nous cherchons les restaurants avec un score inférieur à 5.
db.restaurants.findOne(
{ "grades.score": { $lt: 5 }},
{ _id: 0, name: 1, borough: 1}
)
De même, si on souhaite tester si un champs a une valeur dans un ensemble donnée, il faut utiliser l’opérateur $in
. Ici, nous cherchons les restaurants de
db.restaurants.findOne(
{ "cuisine": { $in: [ "French", "Italian" ]} },
{ _id: 0, name: 1, borough: 1, cuisine: 1}
)
Enfin, on peut vouloir connaître les valeurs possibles prises par un champs dans les documents. Par exemple, si on veut la liste des quartiers présents dans la base, on fait comme ci-dessous.
db.restaurants.distinct("borough")
Nécessitent une recherche sur la toile pour compléter ce qu’on a déjà vu dans ce TP.