cours-2023-2024 | Documents de mes cours pour l'année 2023-2024 | FX Jollois
Base de données NoSQL de type Document Store (orienté document)
Objectifs :
Plus d’informations sur leur site
Principe de base : les données sont des documents
BSON)collections
    JSONJavaScript Object Notation, créé en 2005{ "nom": "jollois", "prenom": "fx" }[ 1, 5, 10]string et number) et trois constantes (true, false, null)Validation possible du JSON sur jsonlint.com/
JSON{
    "address": {
        "building": "469",
        "coord": [
            -73.9617,
            40.6629
        ],
        "street": "Flatbush Avenue",
        "zipcode": "11225"
    },
    "borough": "Brooklyn",
    "cuisine": "Hamburgers",
    "grades": [
        {
            "date": "2014-12-30 01:00:00",
            "grade": "A",
            "score": 8
        },
        {
            "date": "2014-07-01 02:00:00",
            "grade": "B",
            "score": 23
        }
    ],
    "name": "Wendy'S",
    "restaurant_id": "30112340"
}
BSON : extension de JSON
Schéma dynamique
ALTER TABLE ou de redesign de la basefind() : pour tout ce qui est restriction et projectionaggregate() : pour tout ce qui est calcul de variable, d’aggrégats et de manipulations diversesUtilisation du package pymongo
A l’IUT, Il faut l’installer via Anaconda Prompt, avec la ligne de commande suivante
$ pip install pymongo[srv]
pymongo.MongoClient()import pymongo
URI = 'mongodb+srv://user:user@cluster0.ougec.mongodb.net/test'
client = pymongo.MongoClient(URI) # enlever le paramètre URI si connexion locale
db = client.test
restaurantsDans ce document, nous allons travailler sur une base des restaurants New-Yorkais.
Voici le premier document est présenté ci-dessous sur les plus de 25000 restaurants new-yorkais (base de test fournie par Mongo)
{
        "_id" : ObjectId("58ac16d1a251358ee4ee87de"),
        "address" : {
                "building" : "469",
                "coord" : [
                        -73.961704,
                        40.662942
                ],
                "street" : "Flatbush Avenue",
                "zipcode" : "11225"
        },
        "borough" : "Brooklyn",
        "cuisine" : "Hamburgers",
        "grades" : [
                {
                        "date" : ISODate("2014-12-30T00:00:00Z"),
                        "grade" : "A",
                        "score" : 8
                },
                {
                        "date" : ISODate("2014-07-01T00:00:00Z"),
                        "grade" : "B",
                        "score" : 23
                },
                {
                        "date" : ISODate("2013-04-30T00:00:00Z"),
                        "grade" : "A",
                        "score" : 12
                },
                {
                        "date" : ISODate("2012-05-08T00:00:00Z"),
                        "grade" : "A",
                        "score" : 12
                }
        ],
        "name" : "Wendy'S",
        "restaurant_id" : "30112340"
}
pythonLes données JSON sont similaires à un dictionnaire python. Pour récupérer le premier document, nous utilisons la fonction find() de l’objet créé m.
d = db.restaurants.find(limit = 1)
d
L’objet retourné est un curseur, et non le résultat. Nous avons celui-ci lorsque nous utilisons d dans une commande telle qu’une transformation en list par exemple.
list(d)
Une fois le résultat retourné (un seul élément ici), le curseur ne renvoie plus rien.
list(d)
count_documents({}) pour dénombrer les documents
    {} est à mettre obligatoirementestimated_document_count()  pour estimer le nombre de documents, à utiliser de préférence en cas de multiples serveurs et de données massivesdb.restaurants.count_documents({})
db.restaurants.estimated_document_count()
Pour sélectionner les documents, nous allons utiliser le paramètre dans la fonction count_documents() (ainsi que dans les fonctions distinct() et find() que nous verrons plus tard).
{} : tous les documents{ "champs": valeur } : documents ayant cette valeur pour ce champs{ condition1, condition2 } : documents remplissant la condition 1 ET la condition 2"champs.sous_champs" : permet d’accéder donc à un sous-champs d’un champs (que celui-ci soit un littéral ou un tableau){ "champs": { "$opérateur": expression }} : utilisation d’opérateurs dans la recherche
    $in : comparaison à un ensemble de valeurs$gt, $gte, $lt, $lte, $ne : comparaison (resp. greater than, greater than or equal, less than, less than or equal, not equal)db.restaurants.count_documents({ "borough": "Brooklyn" })
db.restaurants.count_documents({ "borough": "Brooklyn", "cuisine": "French" })
db.restaurants.count_documents({ "borough": "Brooklyn", "cuisine": { "$in": ["French", "Italian"]} })
db.restaurants.count_documents(
  { 
    "borough": "Brooklyn", 
    "cuisine": { "$in": ["French", "Italian"]}
  }
)
street du champs addressdb.restaurants.count_documents(
  { 
    "address.street": "Franklin Street"
  }
)
db.restaurants.count_documents(
  { 
    "grades.score": 0
  }
)
db.restaurants.count_documents(
  { 
    "grades.score": { "$lte": 5 }
  }
)
On peut aussi voir la liste des valeurs distinctes d’un attribut, avec la fonction distinct().
borough), pour tous les restaurantsdb.restaurants.distinct(key = "borough")
db.restaurants.distinct(
  key = "cuisine",
  query = { "borough": "Brooklyn" }
)
db.restaurants.distinct(
  key = "grades.grade",
  query = { "borough": "Brooklyn" }
)
find() pour réaliser les restrictions et projectionslimit pour n’avoir que les $n$ premiers documentssort pour effectuer un tri des documentsDataFrame (du module pandas)
    Dans la fonction find(), pour choisir les champs à afficher, le deuxième paramètre permet de faire une projection avec les critères suivants :
_id){ "champs": 1 } : champs à afficher{ "champs": 0 } : champs à ne pas afficher_id)
    { "_id": 0, "champs": 1, ...}Toujours dans la fonction find(), il est possible de faire le tri des documents, avec le paramètre sort qui prend un tuple composé de 1 ou plusieurs tuples indiquant les critères de tri
( "champs", 1 ) : tri croissant( "champs", -1 ) : tri décroissantDans ces fonctions, on peut aussi limiter l’exploration à une partie, avec les paramètres suivant :
limit : restreint le nombre de résultats fournisskip : ne considère pas les n premiers documentsNotez le contenu des colonnes address et grades.
import pandas
pandas.DataFrame(list(db.restaurants.find(limit = 5)))
"street" et "borough")c = db.restaurants.find({ "name": "Shake Shack" }, { "address.street": 1, "borough": 1 })
pandas.DataFrame(list(c))
c = db.restaurants.find(
    { "name": "Shake Shack" }, 
    { "_id": 0, "address.street": 1, "borough": 1 }
)
pandas.DataFrame(list(c))
c = db.restaurants.find(
    {"borough": "Queens", "grades.score": { "$gte":  50}},
    {"_id": 0, "name": 1, "grades.score": 1, "address.street": 1},
    limit = 5
)
pandas.DataFrame(list(c))
c = db.restaurants.find(
    {"name": "Shake Shack", "borough": {"$in": ["Queens", "Brooklyn"]}}, 
    {"_id": 0, "address.street": 1, "borough": 1}
)
pandas.DataFrame(list(c))
c = db.restaurants.find(
    {"borough": "Queens", "grades.score": { "$gt":  50}},
    {"_id": 0, "name": 1, "address.street": 1},
    sort = (("address.street", -1), ("name", 1))
)
pandas.DataFrame(list(c))
Nécessitent une recherche sur la toile pour compléter ce qu’on a déjà vu dans ce TP.