# data[].attributes.attachment_link.readable_text
################distinct(), count_documents(), limiter le nombre de documents resultat, agr��gation(aggregate)

from pymongo import MongoClient # type: ignore
import pymongo;
from datetime import datetime
# from datetime import timedelta
import time
# import json
# import pymongo



#d��finir la connexion au serveur de bases de donn��es MongoDB
#dans ce cas, les information d'autghentification par defaut, �� savoir : host=localhost et port=27017
connexion = MongoClient()
#afficher les information de la connexion : host, port, ...
print(connexion)


#dans la suite du code, la variable bd d��signe la base de donn��e nomm��e bdcommerce
bd = connexion["bdcommerce_mongoo2"]

#dans la suite du code, la variable client d��signe la collection nomm��e 'client' de la base de donn��ee bdcommerce
client = bd["client"]

#autre collection
# produit = bd["produit"]

# #cr��er des documents (de nouveaux clients) �� ins��rer, par la suite, dans la collection client 
# c1 = {"idcli":1,"nom":"karimi","prenom":"farid"}
# c2 = {"idcli":1,"nom":"karimi","prenom":"farid",
#         "commandes":
#         [
#         {"idcmde":1,"datecmde": datetime(2000,5,5,10,5,6)},
#         {"idcmde":2,"datecmde": datetime(1980,5,5,10,5,6)}
#         ],
#         "adresse":{"pays":"maroc","ville":"rabat"}
#         }
# #time.time() : renvoyer le nombre de secondes ��coul��es depuis l'Unix epoch (1er janvier 1970 �� 00:00:00 UTC) en utilisant la biblioth��que standard time
# #=>une forme d'exprimer une date (ici la date courante)
# c3= {"idcli":10,"nom":"karimi","prenom":"farid","dateDerniereCommande":time.time()}
# #ins��rer les documents c1, c2 et c3 dans la collection client
# client.insert_one(c1)
# client.insert_one(c2)
# client.insert_one(c3)

# #ins��rer des produits
# produit.insert_many([
#                      {"id":1,"designation":"cahier","prix":90},
#                      {"id":2,"designation":"lavier","prix":100},
#                      {"id":3,"designation":"souris","prix":50},
#                      {"id":4,"designation":"ecran","prix":2000, "qtestock":1000},
#                       {"id":5,"designation":"imprimante","prix":5000}
#                      ])

# #distinct()
# #lister les noms clients, sans duplications
# listeNoms = client.distinct("nom")
# print("Liste des noms clients, sans duplications :")
# for cli in listeNoms[:]:
#         print(cli)

# #count_documents()
# #lister le nombre de clients de la ville de 'k��nitra'
# nbreClis = client.count_documents({'adresse.ville':'k��nitra'})
# print("nombre de clients de la ville de 'k��nitra' :", nbreClis)

# #limiter le nombre de documents resultat
# listeClients = client.find({},{"_id":1})[0:2]
# print("apr��s avoir limit�� le r��sultat:");
# for cli in listeClients:
#         print(cli)

############aggregate()

# #$match, $project
# pipeline = [
#         {"$match" : {"nom":"karimi"}},
#         {"$project" : {"nom":1, "prenom":1}}
# ]

# l1 = client.aggregate(pipeline)
# print("agr��gation avec $match et $project:");
# for cli in l1:
#         print(cli)

# #$group
# pipeline = [
#     {
#         "$group": {
#             "_id": "$nom",
#             "totalAge": {"$sum": "$age"},  # Group by 'nom' and sum the 'age'
#             "moyenneAge": {"$avg": "$age"},
#             "minAge": {"$min": "$age"},
#             "maxAge": {"$max": "$age"}, 
#             "nbreClients": {"$sum": 1}   
#         }
#     }
# ]

# # Execute aggregation
# l2 = client.aggregate(pipeline)
# print("agr��gation avec $group et op��rateurs d'accumulation ($sum, ...):");
# # Loop through the results
# for group in l2: #remark => if 'age' doesn't exist : sum=0, max=0, min=None, avg=None
#     print(f"Name: {group['_id']}")
#     print(f"  Total Age: {group['totalAge']}")
#     if 'moyenneAge' in group and group['moyenneAge'] is not None:
#         print(f"  Average Age: {group['moyenneAge']:.2f}")
#     else:
#         print("  Average Age: Not available")
#     print(f"  Min Age: {group['minAge']}")
#     print(f"  Max Age: {group['maxAge']}")
#     print(f"  Nbre Clients: {group['nbreClients']}")
#     print("-" * 30)

#$sort
pipeline = [
    {"$sort": {"nom": pymongo.ASCENDING, "prenom": pymongo.DESCENDING}} #pymongo.ASCENDING : 1, pymongo.DESCENDING : -1
]
# Execute aggregation query
sorted_docs = client.aggregate(pipeline)
for doc in sorted_docs:
    print(doc)

         ################$sort avec accumulateurs
pipeline = [
    {
        "$group": {
            "_id": "$nom", 
            "moyenneAge": {"$avg": "$age"}
        }
    },
    {
        "$sort": {
            "moyenneAge": -1  # Sort by average age in descending order (-1 for descending)
        }
    }
]
# Execute aggregation query
sorted_docs = client.aggregate(pipeline)
for doc in sorted_docs:
    print(doc)

#$count
nbClis = client.aggregate([
        {"$count":"nombreClis"}
])

if nbClis:
    print(f"Nombre de clients : {list(nbClis)[0]['nombreClis']}")
else:
    print("No clients found.")



# data[].attributes.attachment_link.readable_text
########################projections, find_one()

from pymongo import MongoClient # type: ignore
from datetime import datetime
# from datetime import timedelta
import time
# import json
# import pymongo



#d��finir la connexion au serveur de bases de donn��es MongoDB
#dans ce cas, les information d'autghentification par defaut, �� savoir : host=localhost et port=27017
connexion = MongoClient()
#afficher les information de la connexion : host, port, ...

# print(connexion)


#dans la suite du code, la variable bd d��signe la base de donn��e nomm��e bdcommerce
bd = connexion["bdcommerce_mongoo2"]

#dans la suite du code, la variable client d��signe la collection nomm��e 'client' de la base de donn��ee bdcommerce
client = bd["client"]

#autre collection
produit = bd["produit"]

# #cr��er des documents (de nouveaux clients) �� ins��rer, par la suite, dans la collection client 

# c1 = {"idcli":1,"nom":"karimi","prenom":"farid"}
# c2 = {"idcli":1,"nom":"karimi","prenom":"farid",
#         "commandes":
#         [
#         {"idcmde":1,"datecmde": datetime(2000,5,5,10,5,6)},
#         {"idcmde":2,"datecmde": datetime(1980,5,5,10,5,6)}
#         ],
#         "adresse":{"pays":"maroc","ville":"rabat"}
#         }
# #time.time() : renvoyer le nombre de secondes ��coul��es depuis l'Unix epoch (1er janvier 1970 �� 00:00:00 UTC) en utilisant la biblioth��que standard time
# #=>une forme d'exprimer une date (ici la date courante)
# c3= {"idcli":10,"nom":"karimi","prenom":"farid","dateDerniereCommande":time.time()}
# #ins��rer les documents c1, c2 et c3 dans la collection client
# client.insert_one(c1)
# client.insert_one(c2)
# client.insert_one(c3)

# #ins��rer des produits
# produit.insert_many([
#                      {"id":1,"designation":"cahier","prix":90},
#                      {"id":2,"designation":"lavier","prix":100},
#                      {"id":3,"designation":"souris","prix":50},
#                      {"id":4,"designation":"ecran","prix":2000, "qtestock":1000},
#                       {"id":5,"designation":"imprimante","prix":5000}
#                      ])

# # #lister les clients
# # #l'objet listeClients est un it��rateur qui permet de parcourir les documents renvoy��s par la m��thode find()
# # print("liste des clients :")
# # listeClients = client.find()
# # #afficher les document renvoy��s par find()
# # for cli in listeClients[:]:
# #         print(cli)

#projection => ex : extraire l'idcli et le nom
print("extraire l'idcli et le nom (_id aussi extrait par default) :")
liste = client.find({},{"nom":1,"idcli":1}) #positionner les cl��s �� extraire �� 1
for cli in liste[:]:
        print(cli)

# print("extraire l'idcli et le nom (_id exclu):")
# liste = client.find({},{"nom":1,"idcli":1, "_id":0}) #positionner les cl��s �� extraire �� 1
# for cli in liste[:]:
#         print(cli)

# print("exclure l'idcli et le nom :")
# liste = client.find({},{"nom":0,"idcli":0}) #on positionne les cl��s �� exclure �� 0
# for cli in liste[:]:
#         print(cli)

# #findOne() => retourne le seul document qui v��rifie une condition (le premier est renvoy�� si plusieurs documents v��rifient la condition)
# selection = {"age":{"$gte":20}}
# cli = client.find_one(selection)
# print("infos du seul (ou premier client) ayant l'age >= 20 :")
# if cli is not None:
#        print(cli)

# #avec projection
# selection = {"age":{"$gte":20}}
# cli = client.find_one(selection,{"nom":1,"prenom":1,"age":1,"_id":0}) #en principe, tous les champs sont extraits sauf ceux exclus
# print("infos du seul (ou premier client) ayant l'age >= 20, champs extraits =>nom,prenom,age :")
# if cli is not None:
#        print(cli)




# data[].attributes.attachment_link.readable_text
####################op��rations sur les tableaux

from pymongo import MongoClient # type: ignore
from datetime import datetime
# from datetime import timedelta
import time
# import json
# import pymongo



#d��finir la connexion au serveur de bases de donn��es MongoDB
#dans ce cas, les information d'autghentification par defaut, �� savoir : host=localhost et port=27017
connexion = MongoClient()
#afficher les information de la connexion : host, port, ...

# print(connexion)


#dans la suite du code, la variable bd d��signe la base de donn��e nomm��e bdcommerce
bd = connexion["bdcommerce_mongoo2"]

#dans la suite du code, la variable client d��signe la collection nomm��e 'client' de la base de donn��ee bdcommerce
client = bd["client"]

#autre collection
produit = bd["produit"]

# #cr��er des documents (de nouveaux clients) �� ins��rer, par la suite, dans la collection client 

# c1 = {"idcli":1,"nom":"karimi","prenom":"farid"}
c2 = {"idcli":1,"nom":"karimi","prenom":"farid",
        "commandes":
        [
        {"idcmde":1,"datecmde": datetime(2000,5,5,10,5,6), "qte":1234},
        {"idcmde":2,"datecmde": datetime(1980,5,5,10,5,6)}
        ],
        "adresse":{"pays":"maroc","ville":"rabat"},
        "villeslivraison":["rabat","tanger"]
        }
# #time.time() : renvoyer le nombre de secondes ��coul��es depuis l'Unix epoch (1er janvier 1970 �� 00:00:00 UTC) en utilisant la biblioth��que standard time
# #=>une forme d'exprimer une date (ici la date courante)
# c3= {"idcli":10,"nom":"karimi","prenom":"farid","dateDerniereCommande":time.time()}
# #ins��rer les documents c1, c2 et c3 dans la collection client
# client.insert_one(c1)
# client.insert_one(c2)
# client.insert_one(c3)

# #ins��rer des produits
# produit.insert_many([
#                      {"id":1,"designation":"cahier","prix":90},
#                      {"id":2,"designation":"lavier","prix":100},
#                      {"id":3,"designation":"souris","prix":50},
#                      {"id":4,"designation":"ecran","prix":2000, "qtestock":1000},
#                       {"id":5,"designation":"imprimante","prix":5000}
#                      ])

# #lister les clients
# #l'objet listeClients est un it��rateur qui permet de parcourir les documents renvoy��s par la m��thode find()
# print("liste des clients :")
# listeClients = client.find()
# #afficher les document renvoy��s par find()
# for cli in listeClients[:]:
#         print(cli)

#requ��tes sur les tableaux et les objets
#taille du tableau commandes = 3 ($size)
print("selection 5 : clients ayant 3 commandes :")
selection = {"commandes":{"$size":3}}
liste = client.find(selection)
for cli in liste[:]:
        print(cli)

# print("selection 6 : clients ayant 'Meknes' comme une ville de livraison :")
# #le tableau villeslivraison contient un ��l��ment dont la valeur est ��gale �� meknes
# selection = {"villeslivraison":{"$eq":"meknes"}}
# liste = client.find(selection)
# for cli in liste[:]:
#         print(cli)

# print("selection 8 : clients ayant 'meknes' ou 'rabat' comme des villes de livraison :")
# #exprimer la pr��sence de ville dans la liste avec deux fa��ons diff��rentes => avec utilisation de $eq et sans
# selection = {"$or":[{"villeslivraison":{"$eq":"meknes"}},{"villeslivraison":"rabat"}]}
# liste = client.find(selection)
# for cli in liste[:]:
#         print(cli)

# print("selection 7 : clients ayant AU MOINS une commande dont la quantit�� est sup��rieure �� 100 et qui est faite durant cette ann��e :")
# #faite durant cette ann��e => 1/1/ann��eCourante <= datecmde <= dateCourante
# annee_courante = datetime.now().year
#$elemMatch => v��rifier si au moins un ��l��ment du tableau satisfait un ensemble de conditions
# selection = {
#     "commandes": {
#         "$elemMatch": {
#             "qte": {"$gt":100},
#             "datecmde": {
#                 "$gte": datetime(annee_courante, 1, 1), #1/1/2025
#                 "$lte": datetime.now()
#             }
#         }
#     }
# }
# liste = client.find(selection)
# for cli in liste:
#         print(cli)

# print("selection 9 : clients ayant 'marrakech' comme deuxi��me ville de livraison :")
# selection = {"villeslivraison.1":{"$eq":"marrakech"}}
# liste = client.find(selection)
# for cli in liste[:]:
#         print(cli)

# print("selection 10 : clients ayant la quantit�� de la premi��re commande >= 100 :")
# selection = {"commandes.0.qte":{"$gte":100}}
# liste = client.find(selection)
# for cli in liste[:]:
#         print(cli)

# data[].attributes.attachment_link.readable_text
/*
###############outline
1-mysqldump utility
2-backup databases
3-backup tables
4-using options : --routines, --events, --triggers, --add-drop-database, --add-drop-table
5-restoring databases
*/
/*
###############plan
1- Utilitaire mysqldump
2- Sauvegarde des bases de donn��es
3- Sauvegarde des tables
4- Utilisation des options :
--routines
--events
--triggers
--add-drop-database
--add-drop-table
5- Restauration des bases de donn��es
*/
select user();
create user 'younes'@'%' identified by 'Younes@2024';
grant ALL PRIVILEGES on *.* to 'younes'@'%';


#1-mysqldump utility:
/*
-mysqldump est un utilitaire en ligne de commande fourni par MySQL pour cr��er des sauvegardes logiques de bases de donn��es. 
	Il g��n��re un script SQL qui contient les commandes n��cessaires pour recr��er la structure de la base de donn��es (tables, vues, etc.) 
	et ins��rer les donn��es dans ces structures. Ce script peut ��tre utilis�� pour restaurer la base de donn��es ou la transf��rer vers un autre serveur MySQL.

-dans Windows, l'utilitaire mysqldump est accessible via la ligne de commande DOS

#ref: https://www.sqlshack.com/how-to-backup-and-restore-mysql-databases-using-the-mysqldump-command/
#mysqldump -u [username] ���p[password] -h [host name] [options] [database_name] [tablename] > [dumpfilename.sql]
*/

#2-backup databases
/*
#sauvegrader la bd bdcommerce : root => utilisateur, -p => l'utilisateur utilise un mot de passe pour acc��der au serveur 
mysqldump -u root -p --databases bdcommerce > C:\Sauvegardes_MySQL\sauvegarde_12-1-25.sql

#sp��cifier le mot de passe dans la commande (Younes@2024)
mysqldump -u younes -pYounes@2024 -h localhost bdcommerce2 > C:\Sauvegardes_MySQL\bdcommerce2.sql

#sauvegrader les bd bdcommerce et bdformation :  
mysqldump -u root -p --databases bdcommerce bdformation> C:\Sauvegardes_MySQL\bdcommerce_bdformation
*/

#3-backup tables
/*
#sauvegarder les tables clients et produits (RQ : le backup ne contient pas d'instruction pour cr��er la BD, mais juste la cr��tion de tables et insertions)
mysqldump -u root -p bdcommerce clients produits > bdcommerce-clients_produits.sql
*/

#4-using options : --routines, --events, --triggers, --add-drop-database, --add-drop-table
/*
[#routines : proc��dures stock��es et fonctions]
[#affciher routines => show procedure status; show function status;]
#Option --routines : Inclut les routines dans le fichier de sauvegarde.
#Option --events : Inclut les ��v��nements d��finis dans les bases de donn��es.
#Option --triggers : Inclut les d��clencheurs (triggers) associ��s aux tables dans le fichier de sauvegarde.
#Option --add-drop-database : Ajoute une commande DROP DATABASE avant chaque cr��ation de base de donn��es.
#Option --add-drop-table : Ajoute une commande DROP TABLE avant chaque cr��ation de table.
*/

#5-Restauration des bases de donn��es

#a- aller dans cmd
#b- mysql -u utilisateur
#ap��s
/*
c- ex��cuter les instructions suivantes:
	- modifier le fichier de sauvegarde pour sellectionner la BD dans laquelle restorer les donn��es
    - source C:\Sauvegardes_MySQL\sauvegardex.sql
*/
################autre m��thode pour restaurer la BD
#a- aller dans cmd
#b- mysql -u username -p bd_retore_devowfs < C:\Sauvegardes_MySQL\sauvegarde_8125.sql

# data[].attributes.body
from pymongo import MongoClient # type: ignore
from datetime import datetime
# from datetime import timedelta
import time
# import json
# import pymongo



#définir la connexion au serveur de bases de données MongoDB
#dans ce cas, les information d'autghentification par defaut, à savoir : host=localhost et port=27017
connexion = MongoClient()
#afficher les information de la connexion : host, port, ...

# print(connexion)


#dans la suite du code, la variable bd désigne la base de donnée nommée bdcommerce
bd = connexion["bdcommerce_mongoo2"]

#dans la suite du code, la variable client désigne la collection nommée 'client' de la base de donnéee bdcommerce
client = bd["client"]

#autre collection
produit = bd["produit"]

#créer des documents (de nouveaux clients) à insérer, par la suite, dans la collection client

c1 = {"idcli":1,"nom":"karimi","prenom":"farid"}
c2 = {"idcli":1,"nom":"karimi","prenom":"farid",
        "commandes":
        [
        {"idcmde":1,"datecmde": datetime(2000,5,5,10,5,6)},
        {"idcmde":2,"datecmde": datetime(1980,5,5,10,5,6)}
        ],
        "adresse":{"pays":"maroc","ville":"rabat"}
        }
#time.time() : renvoyer le nombre de secondes écoulées depuis l'Unix epoch (1er janvier 1970 à 00:00:00 UTC) en utilisant la bibliothèque standard time
#=>une forme d'exprimer une date (ici la date courante)
c3= {"idcli":10,"nom":"karimi","prenom":"farid","dateDerniereCommande":time.time()}
#insérer les documents c1, c2 et c3 dans la collection client
client.insert_one(c1)
client.insert_one(c2)
client.insert_one(c3)

#insérer des produits
produit.insert_many([
                     {"id":1,"designation":"cahier","prix":90},
                     {"id":2,"designation":"lavier","prix":100},
                     {"id":3,"designation":"souris","prix":50},
                     {"id":4,"designation":"ecran","prix":2000, "qtestock":1000},
                      {"id":5,"designation":"imprimante","prix":5000}
                     ])

# #lister les clients
# #l'objet listeClients est un itérateur qui permet de parcourir les documents renvoyés par la méthode find()
# print("liste des clients :")
# listeClients = client.find()
# #afficher les document renvoyés par find()
# for cli in listeClients[:]:
#         print(cli)

# #selection => ex : clients ayant le nom="karimi" et prenom="farid"
# print('clients ayant le nom="karimi" et prenom="farid" :')
# selection = {"nom":"karimi","prenom":"farid"}
# listeClients_selection = client.find(selection)
# for cli in listeClients_selection[:]:
#         print(cli)


# #operateurs
# #$ne : pas égal => famille : ($ne, $eq(égal),$gt(supérieur à),$gte(supérieur ou égal),$lt(inférieur à),$lte(inférieur ou égal))
# #$nin : pas dans => famille : ($nin, $in(inclus dans))
# #$exists : si 'true' => le document contient le champ (même si sa valeur est 'null')
# #$exists => famille(opérateurs d'éléments) : ($type : format => { champ: { $type: <type BSON> } }, liste de types => réf : https://www.mongodb.com/docs/manual/reference/operator/query/type/)
# #$and => famille : ($and(on renvoie true si toutes les conditions sont true), $or, $nor(on renvoie true si toutes les conditions sont fausses), $not)

# #$eq : renvoyer les clients dont le nom est égal à sadiki
# print("selection 1 :")
# selection = {"nom": { "$ne" : "sadiki"}}
# liste = client.find(selection)
# for cli in liste[:]:
#         print(cli)

# #renvoyer les clients qui vérifient les conditions suivantes ensemble($and):
#         #le nom est différent de sadiki : $ne
#         #l'age est supérieur ou égal à 30 : $gte
#         #l'age n'est pas inclus dans la liste [30,33] : $nin
#         #condition 1: {"nom":{"$ne":"sadiki"}}, condition 2: {"age":{"$exists":True, "$gte":30, "$nin":[30,33]}}
# print("selection 2 :")
# selection = {"$and":[{"nom":{"$ne":"sadiki"}},{"age":{"$exists":True, "$gte":30, "$nin":[30,33]}}]}
# liste = client.find(selection)
# for cli in liste[:]:
#         print(cli)

# #renvoyer les clients qui vérifient AU MOINS l'une des conditions suivantes:
#         #condition 1 : le prix est de type int($type) et($and) supérieur ou égal à 100($gte)
#         #condition 2 : ils possèdent un champ nommé qtestock ($exists)
# print("selection 3 :")
# selection = {"$or":[{"$and":[{"prix":{"$type":"int"}},{"prix":{"$gte":100}}]} , {"qtestock":{"$exists":True}}]}
# liste = produit.find(selection)
# for prod in liste[:]:
#         print(prod)

# #renvoyer les clients dont le telephone est de la forme suivante ($regex) :
#         #commence par 06 : ^06 (^ désigne le début)
#         #se termine par 8 chiffres : (\d){8}$ ($ désigne la fin)
# print("selection 4 (regex) :")
# selection = {"telephone":{"$regex":"^06(\d){8}$"}} #metacharacters => ref : https://www.w3schools.com/python/python_regex.asp
# liste = client.find(selection)
# for cli in liste[:]:
#         print(cli)

# data[].attributes.body
from pymongo import MongoClient # type: ignore
from datetime import datetime
# from datetime import timedelta
import time
# import json
# import pymongo



#définir la connexion au serveur de bases de données MongoDB
#dans ce cas, les information d'autghentification par defaut, à savoir : host=localhost et port=27017
connexion = MongoClient()
#afficher les information de la connexion : host, port, ...
print(connexion)


#dans la suite du code, la variable bd désigne la base de donnée nommée bdcommerce
bd = connexion["bdcommerce_mongoo2"]

#dans la suite du code, la variable client désigne la collection nommée 'client' de la base de donnéee bdcommerce
client = bd["client"]

#autre collection
produit = bd["produit"]

#créer des documents (de nouveaux clients) à insérer, par la suite, dans la collection client

c1 = {"idcli":1,"nom":"karimi","prenom":"farid"}
c2 = {"idcli":1,"nom":"karimi","prenom":"farid",
        "commandes":
        [
        {"idcmde":1,"datecmde": datetime(2000,5,5,10,5,6)},
        {"idcmde":2,"datecmde": datetime(1980,5,5,10,5,6)}
        ],
        "adresse":{"pays":"maroc","ville":"rabat"}
        }
#time.time() : renvoyer le nombre de secondes écoulées depuis l'Unix epoch (1er janvier 1970 à 00:00:00 UTC) en utilisant la bibliothèque standard time
#=>une forme d'exprimer une date (ici la date courante)
c3= {"idcli":10,"nom":"karimi","prenom":"farid","dateDerniereCommande":time.time()}
#insérer les documents c1, c2 et c3 dans la collection client
client.insert_one(c1)
client.insert_one(c2)
client.insert_one(c3)

#insérer des produits
produit.insert_many([
                     {"id":1,"designation":"cahier","prix":90},
                     {"id":2,"designation":"lavier","prix":100},
                     {"id":3,"designation":"souris","prix":50},
                     {"id":4,"designation":"ecran","prix":2000, "qtestock":1000},
                      {"id":5,"designation":"imprimante","prix":5000}
                     ])

#lister les clients
#l'objet listeClients est un itérateur qui permet de parcourir les documents renvoyés par la méthode find()
print("liste des clients :")
listeClients = client.find()
#afficher les document renvoyés par find()
for cli in listeClients[:]:
        print(cli)

# data[].attributes.attachment_link.readable_text
#ref : https://www.mysqltutorial.org/mysql-error-handling-in-stored-procedures/
#for MySQL error codes and states => https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-error-sqlstates.html, pour MySQL 5.0 
#(en fran��ais)=> https://mysql.developpez.com/tutoriels/manuel-de-reference-mysql-5-0/?page=Gestion-des-erreurs-avec-MySQL 

/*DECLARE
CONTINUE|EXIT|UNDO 
HANDLER
FOR mysql_error_code|SQLSTATE sqlstate_value|condition_name|SQLWARNING|NOT FOUND|SQLEXCEPTION
statement
*/
#SQLWARNING, #NOT FOUND, et SQLEXCEPTION sont des classes de SQLSTATE

use bdcommerce;
############################ exception avec l'action 'exit' et la valeur d'action 'mysql_error_code' (dans ce cas le code 1062)
#on quitte la proc��dure d��s que l'exception est lev��e

drop procedure if exists ajouterCli;
delimiter $$
create procedure ajouterCli(id int)
begin
	declare continue handler for 1062
		select 'enregistrement dupliqu��' as 'message d''erreur';
        
    insert into client(idcli) values(id);
    select count(*) as '# Enregistrements apr��s insertion' from client;
end$$

call ajouterCli(10);

select * from client;
############################ exception avec l'action 'continue' et la valeur d'action 'SQLSTATE sqlstate_value' (dans ce cas l'etat 23000)
#les traitements se poursuivent apr��s la lev��e de l'exception

drop procedure if exists ajouterCli2;
delimiter $$
create procedure ajouterCli2(id int)
begin
	declare continue handler for SQLSTATE '23000'
		select 'exception avec l''etat 23000' as 'message d''erreur';
    
    insert into client(idcli) values(id);
    select count(*) as '# Enregistrements apr��s insertion' from client;
end$$

call ajouterCli2(6);

############################ exception avec la valeur d'action 'SQLEXCEPTION'
drop procedure if exists ajouterCli3;
delimiter $$
create procedure ajouterCli3(id int)
begin
	declare exit handler for SQLEXCEPTION
    select 'exception de classe SQLEXCEPTION' as 'message d''erreur';
    
    insert into client(idcli) values(id);
    select count(*) as '# Enregistrements apr��s insertion' from client;
end$$

call ajouterCli3(6);

############################ exception avec la valeur d'action 'SQLWARNING'
update client set prenom = null;
alter table client modify column prenom varchar(3);
delimiter $$
create procedure ajouterCli4(id int, p varchar(50))
begin
	declare continue handler for SQLWARNING
    select 'exception de classe SQLWARNING : donn��es vont ��tre tronqu��es' as 'message d''avertissement';
    
    insert into client(idcli, prenom) values(id, p);
    select count(*) as '# Enregistrements apr��s insertion' from client;
end$$

call ajouterCli4(7, 'kamal');

select * from client;

############################ exceptions nomm��es
create table if not exists logCli(cli int);
drop procedure if exists ajouterCliProd;
delimiter $$
create procedure ajouterCliProd(cli int, prod int)
begin
    declare exceptionCli condition for 1062; #code d'erreur
    declare exceptionProd condition for sqlstate '42S02'; #valeur d'etat => table or view not found
	declare continue handler for exceptionCli
    begin
		insert into logCli values(cli);
		select 'exception nomm��e avec un code d''erreur' as 'exception cli';
    end;
    declare exit handler for exceptionProd
    begin
		select 'exception nomm��e avec une valeur d''etat' as 'exception prod';
    end;
    insert into client(idcli) values(cli);
    insert into produittt(idprod) values(prod); #table produittt n'existe pas dans la BD
end$$

call ajouterCliProd(1, 13);

select * from client; select * from produit; select * from logCli;

#################################### instruction SIGNAL
/*
The SIGNAL query is a mechanism used to return a warning or error message appearing during the execution of a 
stored program, such as stored procedure, trigger or event, or stored function. This statement provides 
error information to an error handler, the outer portion of an application, or the client.
*/
drop procedure if exists CommandesCli;
delimiter $$
create procedure CommandesCli(cli int)
begin
	select count(*) into @nombreCmdes from commandes where idcli = cli;
    if @nombreCmdes = 0 then
		signal sqlstate '03111'
        set MESSAGE_TEXT = 'Ce client n''a pas de commandes' , MYSQL_ERRNO = 10;
    end if;
    select @nombreCmdes as '# Cmdes du client';
end$$

call CommandesCli(1111);

show errors;

select * from commandes;
select * from clients;
############################ instruction RESIGNAL (et SIGNAL avec condition nomm��e)
/*
MySQL provides RESIGNAL statement for raising a warning or error condition similar to the SIGNAL statement 
in terms of functionality and syntax, except that:
-The RESIGNAL statement must be used within an error or warning handler themselves. Otherwise, MySQL generates 
  an error message: RESIGNAL when the handler is not active.
-The RESIGNAL statement can be used without any attributes, even the SQLSTATE value or attributes as in 
  the SIGNAL statement.
*/
drop procedure if exists diviser;
DELIMITER $$
CREATE PROCEDURE diviser(IN numerateur INT, IN denominateur INT, OUT resultat double)
BEGIN
	DECLARE division_par_zero CONDITION FOR SQLSTATE '22012';
	DECLARE CONTINUE HANDLER FOR division_par_zero
		RESIGNAL SET MESSAGE_TEXT = 'erreur : le denominateur ne peut pas ��tre nul', MYSQL_ERRNO = '2222';
	IF denominateur = 0 THEN
		SIGNAL division_par_zero;
	ELSE
		SET resultat := numerateur/denominateur;
	END IF;
END$$

call diviser(1, 0, @r);
select @r;

/************** Afficher les erreurs (code + SQLState)********************************/
SELECT * FROM performance_schema.events_errors_summary_global_by_error;

#delete from client where idcli= 1;

select * from commande
delete from produit where idprod = 2

drop function if exists f3;
delimiter $$
create function f3(x int) returns float
deterministic
begin
	#declare x  float default 0;
    declare y float;
    set y = 1/x;
    return y;
end$$

delimiter ;
select @z := f3(0);

########################supplement added on 07/10/2024
drop function if exists f_info_exception;
delimiter $
create function f_info_exception()
returns varchar(50)
begin
	declare error_state, error_string, error_code varchar(20);
	declare exit handler
    for 1451, 1062
    begin
        GET DIAGNOSTICS CONDITION 1                                      #CONDITION 1: This specifies the condition number to retrieve. When multiple errors or warnings occur during execution, they are indexed in sequence (e.g., CONDITION 1, CONDITION 2, etc.). CONDITION 1 refers to the first error or warning that occurred.
        error_state = RETURNED_SQLSTATE, 
        error_string = MESSAGE_TEXT,
        error_code = MYSQL_ERRNO;
        
        return concat(error_state, '|', error_string, '|', error_code);
    end;    
    insert into clients(idcli) values(1);
    delete from clients where idcli=1;
end$;
delimiter ;

select f_info_exception();

select * from commandes;
				########## NOT FOUND (doesn't work with this case)
drop procedure if exists not_found_proc;
delimiter $$
create procedure not_found_proc(cli int)
begin
	declare exit handler for not found
    begin
		select 'client doesn''t exist' as 'error message';
    end;
		select * from clients where idcli=cli;
end$$

delimiter ;

call not_found_proc(333);

# data[].attributes.headline
Fonction SQL : Nombre de Commandes par Client et Produit .Sabari Nabila

# data[].attributes.subject
Fonction SQL : Nombre de Commandes par Client et Produit .Sabari Nabila

# data[].attributes.attachment_link.readable_text
DROP FUNCTION IF EXISTS nbCommandesCliProd;
DELIMITER $$
CREATE FUNCTION nbCommandesCliProd(nomClient VARCHAR(50), designationProduit VARCHAR(50))
RETURNS INT
READS SQL DATA
BEGIN
    DECLARE nombreCommandes INT;

    SET nombreCommandes = (
        SELECT COUNT(*)
        FROM commandes c
        JOIN clients cli ON c.id_client = cli.id_client
        JOIN produits p ON c.id_produit = p.id_produit
        WHERE cli.nom = nomClient
        AND p.designation = designationProduit
    );
    RETURN nombreCommandes;
END $$
DELIMITER ;

# data[].attributes.attachment_link.readable_text
from pymongo import MongoClient
from datetime import datetime
#from datetime import timedelta
import time
import json
import pymongo


connexion = MongoClient()
print(connexion)


bd = connexion["bdcommerce"]


client = bd["client"]


produit = bd["produit"]

listeClients = client.find()
print("clients")
for cli in listeClients[:]:                             
       print(cli)

listeProduits = produit.find()
print("\n\n\nproduits")
for prod in listeProduits:                             
       print(prod)

####################################################
#regrouper les clients (dont l'idcli est sup��rieur ou ��gal �� 10) par nom,
#on renvoie pour chaque groupe le nom et l'age minimal 
#rq : 
       #on prend en consid��ration seulement les clients qui poss��dent les champs idcli et age
       #pour les clients ayant un age et un idcli, on renvoie None pour le nom, ex : {'nom: None, age minimal : 33'}
groupes = client.aggregate(
        [
                {"$match":{"idcli":{"$gte":10}}}
                ,
                {"$group":{"_id":"$nom", "age_minimal":{"$min":"$age"}}}
        ]
)
print("\n\n\nclients group��s : ")
for gpe in groupes:
       print('nom: ' + str(gpe['_id']) + ', age minimal : ' + str(gpe['age_minimal'])) #format d'affichage => nom: karimi, age minimal : 45
       #print(gpe) # format de l'affichage => {'_id': 'karimi', 'age_minimal': '45'}

#regroupement par nom et prenom, 
       #on renvoie l'age minimal et maximal, la somme et la moyenne des ages, ainsi que le nombre de documents par groupe
#rq:
       #on prend en consid��ration m��me les documents qui n'ont pas de champ age
       #pour les documents qui n'ont pas de nom, on se contente du prenom
       #si tous les documents du groupe ne poss��dent pas le champ age, on renvoie None pour min, max, avg, et 0 pour la somme (voir la conversion dans la requ��te) 
       #si quelques documents dans le groupe ne piss��dent pas l'age, ils ne sont pas prise en consid��ration dans les op��rations arithm��tiques et dans le recherche du min et max

accumulateur2 = client.aggregate([
    # ��tape 1 : Filtre les documents o�� le champ age existe
    #{"$match": {"age": {"$exists": True}}},

    # ��tape 2 : Convertit le champ age en num��rique
    {"$addFields": {"age_numeric": {"$convert": {"input": "$age", "to": "double", "onError": 0}}}},
    
    # ��tape 3 : Regroupe par nom et pr��nom et calcule les statistiques d'��ge
    {"$group": {
        "_id": {"nom": "$nom", "prenom": "$prenom"},
        "age_min": {"$min": "$age_numeric"},
        "age_max": {"$max": "$age_numeric"},
        "age_sum": {"$sum": "$age_numeric"},
        "age_avg": {"$avg": "$age_numeric"},
        "age_count": {"$sum": 1},  # Comptage des documents dans le groupe
        "age_count_2":{"$count":{}} #autre fa��on pour recup��rer le nombre de documents; count ne prend pas d'arguments
    }}
])


print("\n\n\nregroupement par nom et prenom:")
for e in accumulateur2:
        print(e)

#tri par nom (dans l'ordre croissant => 1) et prenom (dans l'ordre d��croissant => -1) 
        #apr��s regroupement par nom et prenom 
#rq:
        #les groupes qui ne ne poss��dent pas le champ nom apparaissent en premier lieu
accumulateurTri = client.aggregate(
        [
                {
                        "$group":
                        {
                        "_id":{"nom":"$nom","prenom":"$prenom"},
                        "age_min":{"$min":"$age"},
                        "idpremierclient":{"$first":"$idcli"}       
                        }
                },
                {
                        "$sort":{"_id.nom":1, "_id.prenom":-1}
                }
        ]
) 
print("\n\n\ntri par nom et prenom apr��s regroupement :")
for e in accumulateurTri:
        print(e)

#Tri par nom et age (m��me si l'age n'est pas renvoy�� par la requ��te)
#!!!!!!!!!!!Attention: dans le cas suivant l'age n'est pas pris en consid��ration dans le tri!!!!!!!!!!!
        #pour que l'age soit op��rationnel dans le tri, on l'inclut dans le pipeline $project
tri = client.aggregate(
        [
        {"$project":{"nom":1,"prenom":1, "idcli":1, "_id":0}}, #seuls les champs 'nom', 'prenom' et idcli sont affich��s
        {"$sort":{"nom":1, "age":1}} #tri croissant par nom (1), PUIS d��croissant par age (-1)
        ]
)
print("\n\n\ntri par nom et age (m��me si l'age n'est pas renvoy�� par la requ��te):")
print("Attention!!!!!!!!!!!!!!!!!!!!!!!!!!!")
for e in tri:
        print(e)


#Distinct() => recup��rer les noms distincts (en eliminant les doublons)
noms_distinct = client.distinct("nom")
print("\n\n\nnoms distincts :")
for n in noms_distinct[:]:
        print(n)

#renvoyer les noms distincts pour les documents qui respectent la condition : le champ age existe
#rq:
        #le nom N'EST PAS renvoy�� dans le cas o�� TOUS les champs n'ont pas de champ age
nomsquery_distinct = client.distinct("nom",{"age":{"$exists":True}})
print("\n\n\nnoms distincts avec condition :")
for nq in nomsquery_distinct[:]:
        print(nq)

#une fa��on de renvoyer les doublets (nom,prenom) distincts
nomsprenoms_distinct = client.aggregate(
        [
                {
                "$group": {"_id":{"nom":"$nom","prenom":"$prenom"}}
                }
        ]
)
print("\n\n\n(noms,prenoms) distincts :")
for np in nomsprenoms_distinct:
        print(np)


#Requ��tes de modifications
#mise �� jour

#modifier le premier document qui v��rifie une condition donn��e
maj1 = client.update_one(
        {'nom':'sadiki'}, #condition
        {"$set":{"nom":"halimi","prenom":"halima"},"$inc":{"age":1}} #$set => modifier le champ, $inc => incrementer(|decrementer (valeur negative)) le champ
)
print("maj1: nombre de documents v��rifiant la condition : ", maj1.matched_count) #valeur maximale est 1 ou 0
print("maj1: nombre de documents modifi��s : ", maj1.modified_count) #1 => valeur maximale est 1 ou 0


maj2 = client.update_many(
        #{"nom":{"$eq":"sadiki"}}, 
       {},
        {"$inc":{"age":1000}}, 
        upsert=True             #si le champ 'age' n'existe pas, on l'ajoute (on lui affecte la valeur d'incermentation : 1000) 
)
print("maj2 nombre de documents v��rifiant la condition : ", maj2.matched_count) 
print("maj2 nombre de documents modifi��s : ", maj2.modified_count) 


#augmenter de 10% les quantit��s des commandes faites par les clients dont le nom est karimi 
maj3 = client.update_many(
    {
        "commandes": {"$exists": True},  # le champ "commandes" DOIT exister
        "commandes.qte": {"$type": "int"}  # le champ "qte" doit ��tre de type int
    }, 
    {"$mul": {"commandes.$[].qte": 1.1}}  # Op��rateur $mul pour multiplier les quantit��s par 1.1 (pour augmenter de 10%)
)
print("maj r��ussie")

# ajouter le champ "nationalite" au client de l'idcli=14
client.update_one(
    { "idcli": 14 },
    { "$set": { "nationalite": "Turquie" } }  # Utilisation de $set pour ajouter le champ "nationalite"
)

# Requ��te pour supprimer le champ "age" du client de l'idcli=100
client.update_one(
    { "idcli": 100 },
    { "$unset": { "age": "" } }  # Utilisation de $unset pour supprimer le champ "age"
)

#suppression
suppression_unique = client.delete_one({"nom":"karimi"})
print("suppression d'un document unique (ou le premier):")
print("nombre de documents supprim��s: ",suppression_unique.deleted_count)

suppression_multiple = client.delete_many({"nom":"karimi"})
print("suppression de plusieurs documents:")
print("nombre de documents supprim��s : ",suppression_multiple.deleted_count)

# data[].attributes.attachment_link.readable_text
from pymongo import MongoClient
from datetime import datetime
from datetime import timedelta
import time
import json
import pymongo



#d��finir la connexion au serveur de bases de donn��es MongoDB
#dans ce cas, les information d'autghentification par defaut, �� savoir : host=localhost et port=27017
connexion = MongoClient()
#afficher les information de la connexion : host, port, ...
print(connexion)


#dans la suite du code, la variable bd d��signe la base de donn��e nomm��e bdcommerce
bd = connexion["bdcommerce"]

#dans la suite du code, la variable client d��signe la collection nomm��e 'client' de la base de donn��ee bdcommerce
client = bd["client"]

#autre collection
produit = bd["produit"]

#cr��er des documents (de nouveaux clients) �� ins��rer, par la suite, dans la collection client 

c1 = {"idcli":1,"nom":"karimi","prenom":"farid"}
c2 = {"idcli":1,"nom":"karimi","prenom":"farid",
        "commandes":
        [
        {"idcmde":1,"datecmde": datetime(2000,5,5,10,5,6)},
        {"idcmde":2,"datecmde": datetime(1980,5,5,10,5,6)}
        ],
        "adresse":{"pays":"maroc","ville":"rabat"}
        }
#time.time() : renvoyer le nombre de secondes ��coul��es depuis l'Unix epoch (1er janvier 1970 �� 00:00:00 UTC) en utilisant la biblioth��que standard time
#=>une forme d'exprimer une date (ici la date courante)
c3= {"idcli":10,"nom":"karimi","prenom":"farid","dateDerniereCommande":time.time()}
#ins��rer les documents c1, c2 et c3 dans la collection client
client.insert_one(c1)
client.insert_one(c2)
client.insert_one(c3)

#ins��rer des produits
produit.insert_many([
                     {"id":1,"designation":"cahier","prix":90},
                     {"id":2,"designation":"lavier","prix":100},
                     {"id":3,"designation":"souris","prix":50},
                     {"id":4,"designation":"ecran","prix":2000, "qtestock":1000},
                      {"id":5,"designation":"imprimante","prix":5000}
                     ])

#lister les clients
#l'objet listeClients est un it��rateur qui permet de parcourir les documents renvoy��s par la m��thode find()
print("liste des clients :")
listeClients = client.find()
#afficher les document renvoy��s par find()
for cli in listeClients[:]:
        print(cli)

#heures des derni��res commandes
#ctime() : convertir un temps donn�� en secondes depuis l'Unix epoch en une cha��ne de caract��res repr��sentant une date et une heure lisible par l'homme
print("dates des derni��res commandes :")
listeClients = client.find()
for cli in listeClients[:]:                             
        if "dateDerniereCommande" in cli.keys():       #cli est un dictionnaire (rappel : document sous format JSON)
                print(time.ctime(cli["dateDerniereCommande"])) 


#ref => https://www.mongodb.com/docs/manual/reference/operator/
#ref (selection & projection) => https://www.analyticsvidhya.com/blog/2020/08/query-a-mongodb-database-using-pymongo/
#selection => ex : clients ayant le nom="karimi" et prenom="farid"
print('clients ayant le nom="karimi" et prenom="farid" :')
selection = {"nom":"karimi","prenom":"farid"}
listeClients_selection = client.find(selection)
for cli in listeClients_selection[:]:
        print(cli)


#operateurs
#$ne : pas ��gal => famille : ($ne, $eq(��gal),$gt(sup��rieur ��),$gte(sup��rieur ou ��gal),$lt(inf��rieur ��),$lte(inf��rieur ou ��gal))
#$nin : pas dans => famille : ($nin, $in(inclus dans))
#$exists : si 'true' => le document contient le champ (m��me si sa valeur est 'null')
#$exists => famille(op��rateurs d'��l��ments) : ($type : format => { champ: { $type: <type BSON> } }, liste de types => r��f : https://www.mongodb.com/docs/manual/reference/operator/query/type/) 
#$and => famille : ($and(on renvoie true si toutes les conditions sont true), $or, $nor(on renvoie true si toutes les conditions sont fausses), $not)

#$eq : renvoyer les clients dont le nom est ��gal �� sadiki
print("selection 1 :")
selection = {"nom": { "$eq" : "sadiki"}}
liste = client.find(selection)
for cli in liste[:]:
        print(cli)

#renvoyer les clients qui v��rifient les conditions suivantes ensemble($and):
        #le nom est diff��rent de sadiki : $ne
        #l'age est sup��rieur ou ��gal �� 30 : $gte
        #l'age n'est pas inclus dans la liste [30,33] : $nin 
        #condition 1: {"nom":{"$ne":"sadiki"}}, condition 2: {"age":{"$exists":True, "$gte":30, "$nin":[30,33]}}
print("selection 2 :")
selection = {"$and":[{"nom":{"$ne":"sadiki"}},{"age":{"$gte":30, "$nin":[30,33]}}]}
liste = client.find(selection)
for cli in liste[:]:
        print(cli)

#renvoyer les clients qui v��rifient AU MOINS l'une des conditions suivantes:  
        #condition 1 : le prix est de type int($type) et($and) sup��rieur ou ��gal �� 100 
        #condition 2 : ils poss��dent un champ nomm�� qtestock ($exists)
print("selection 3 :")
selection = {"$or":[{"$and":[{"prix":{"$type":"int"}},{"prix":{"$gte":100}}]} , {"qtestock":{"$exists":True}}]}
liste = produit.find(selection)
for prod in liste[:]:
        print(prod)

#renvoyer les clients dont le telephone est de la forme suivante ($regex) : 
        #commence par 06 : ^06 (^ d��signe le d��but)
        #se termine par 8 chiffres : (\d){8}$ ($ d��signe la fin)
print("selection 4 (regex) :")
selection = {"telephone":{"$regex":"^06(\d){8}$"}} #metacharacters => ref : https://www.w3schools.com/python/python_regex.asp
liste = client.find(selection)
for cli in liste[:]:
        print(cli)

#requ��tes sur les tableaux et les objets
#taille du tableau commandes = 2 ($size)
print("selection 5 : clients ayant 2 commandes :")
selection = {"commandes":{"$size":2}}
liste = client.find(selection)
for cli in liste[:]:
        print(cli)

print("selection 6 : clients ayant 'Meknes' comme une ville de livraison :")
#le tableau villeslivraison contient un ��l��ment dont la valeur est ��gale �� meknes
selection = {"villeslivraison":{"$eq":"meknes"}}
liste = client.find(selection)
for cli in liste[:]:
        print(cli)

print("selection 7 : clients ayant AU MOINS une commande dont la quantit�� est sup��rieure �� 100 et qui est faite durant cette ann��e :")
#faite durant cette ann��e => 1/1/ann��eCourante <= datecmde <= dateCourante
annee_courante = datetime.now().year
selection = {
    "commandes": {
        "$elemMatch": {
            "qte": {"$gt":100},
            "datecmde": {
                "$gte": datetime(annee_courante, 1, 1),
                "$lte": datetime.now()
            }
        }
    }
}
liste = client.find(selection)
for cli in liste:
        print(cli)

print("selection 8 : clients ayant 'meknes' ou 'rabat' comme des villes de livraison :")
#exprimer la pr��sence de ville dans la liste avec deux fa��ons diff��rentes => avec utilisation de $eq et sans
selection = {"$or":[{"villeslivraison":{"$eq":"meknes"}},{"villeslivraison":"rabat"}]}
liste = client.find(selection)
for cli in liste[:]:
        print(cli)

print("selection 9 : clients ayant 'marrakech' comme deuxi��me ville de livraison :")
selection = {"villeslivraison.1":{"$eq":"marrakech"}}
liste = client.find(selection)
for cli in liste[:]:
        print(cli)

print("selection 10 : clients ayant la quantit�� de la premi��re commande >= 100 :")
selection = {"commandes.0.qte":{"$gte":100}}
liste = client.find(selection)
for cli in liste[:]:
        print(cli)

#projection => ex : extraire l'idcli et le nom
print("extraire l'idcli et le nom (_id aussi extrait par default) :")
liste = client.find({},{"nom":1,"idcli":1}) #positionner les cl��s �� extraire �� 1
for cli in liste[:]:
        print(cli)

print("extraire l'idcli et le nom (_id exclu):")
liste = client.find({},{"nom":1,"idcli":1, "_id":0}) #positionner les cl��s �� extraire �� 1
for cli in liste[:]:
        print(cli)

print("exclure l'idcli et le nom :")
liste = client.find({},{"nom":0,"idcli":0}) #on positionne les cl��s �� exclure �� 0
for cli in liste[:]:
        print(cli)

#findOne() => retourne le seul document qui v��rifie une une condition (le premier est renvoy�� si plusieurs documents v��rifient la condition)
selection = {"age":{"$gte":20}}
cli = client.find_one(selection)
print("infos du seul (ou premier client) ayant l'age >= 20 :")
if cli is not None:
       print(cli)

#avec projection
selection = {"age":{"$gte":20}}
cli = client.find_one(selection,{"nom":1,"prenom":1,"age":1,"_id":0}) #en principe, tous les champs sont extraits sauf ceux exclus
print("infos du seul (ou premier client) ayant l'age >= 20, champs extraits =>nom,prenom,age :")
if cli is not None:
       print(cli)

#op��rations arithm��tiques
#ajouter une collection nomm��e col
col = bd["col"]
col.insert_one({"x":-80,"y":3,"dat":datetime(2000,4,7)})
print("col:")
selection = col.find({})
#strftime() : formater la date pour l'afficher sous un format qui ressemble �� cela : 07/02/2000
for doc in selection[:]:
        print("x:",doc["x"],"y:",doc["y"],"dat:",doc["dat"].strftime("%d/%m/%Y"))

print('op��rations arithm��tiques:')
#projection en utilisant $project => on peut nommer les cl��s d'une mani��re personnalis��e
selection = col.aggregate(
        [
                {"$project":{
                        "x":1,
                        "y":1,
                        "somme":{"$add":["$x","$y"]}, #la cl�� nomm��e somme porte la valeur qui correspond �� la somlme de valeur de x et celle de y
                        "soustraction":{"$subtract":["$x","$y"]}, #soustraction
                        "produit":{"$multiply":["$x","$y"]},
                        "division":{"$divide":["$x","$y"]},
                        "modulo":{"$mod":["$x","$y"]}, #modulo : reste de la division
                        "_id":0
                }}
        ]
)
for doc in selection:
        print("x:",doc["x"],"y:",doc["y"],"somme:",doc["somme"],
                "soustraction:",doc["soustraction"],"produit:",doc["produit"],"division:",
                doc["division"],"modulo:",doc["modulo"])

#condition
#si x >= 0 alors : absX = x, sinon : absx = x*(-1)
selection = col.aggregate(
        [
                {
                        "$project":{
                                "x":1,
                                "absX":{"$cond":{"if":{"$gte":["$x",0]},"then":"$x","else":{"$multiply":["$x",-1]}}},
                                "_id":0
                        }
                }
        ]
)
print("valeurs absolues de x:")
for X in selection:
        print("x : ",X["x"],", |x| : ",X["absX"])

#let
print("extraire l'idcli et la quantit�� de la premi��re commande de chaque client:")
#pour les clients qui ne poss��dent ni l'idcli ni la qte de la premi��re commande, on renvoie : {}
liste = client.aggregate(
        [
        {"$project": {
        "_id":0,
        "idcli":1,
        "qtepremierecommande": {
          "$let": {
            "vars": {
              "firstMember": {
                "$arrayElemAt": ["$commandes",0]
              }
            },
            "in": "$$firstMember.qte"   #dans ce cas '$$firstMember' repr��sente le premier ��l��ment du tableau 'commandes'
          }
        }
      }
    }
        ]
)
for cli in liste:
        print(cli)


#comment exprimer des jointures
bdformation = connexion["bdformation"]
stagiaire = bdformation["stagiaire"]
filiere = bdformation["filiere"]
"""
stagiaire.insert_many([
        {"cne":"100000","nom":"karimi","prenom":"farid","filiere":1},
        {"cne":"100001","nom":"sadiki","prenom":"farid","filiere":2},
        {"cne":"100002","nom":"karimi","prenom":"halima","filiere":1},
        {"cne":"100003","nom":"chakiri","prenom":"amina"},
])
filiere.insert_many([
        {"numero":1,"designation":"D��veloppement Digital"},
        {"numero":2,"designation":"Infrastructure Digitale"},
        {"numero":3,"designation":"Gestion des entreprises"},
])
"""

#jointure interne
print('jointure interne (on affecte �� chaque stagiaire sa filiere) :')
#exemple du r��sultat obtenu : {'_id': ObjectId('65b906f041549398b58b27da'), 'cne': '100000', 'nom': 'karimi', 'prenom': 'farid', 'filiere': [{'_id': ObjectId('65b906f841549398b58b27de'), 'numero': 1, 'designation': 'D��veloppement Digital'}]}  
selection = stagiaire.aggregate([
                        {
                                "$match":{
                                        "filiere":{"$exists":True}
                                }
                        },
                        {
                        "$lookup":
                                {
                                "from":"filiere",
                                "localField":"filiere",
                                "foreignField":"numero",
                                "as":"filiere"
                                }
                        }
        ])
print("stagiaires avec leurs fili��res:")
for s in selection:
        print(s)
