IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

NoSQL Discussion :

[MongoDB] Requête NoSql avec MongoDB


Sujet :

NoSQL

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2017
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2017
    Messages : 6
    Points : 7
    Points
    7
    Par défaut [MongoDB] Requête NoSql avec MongoDB
    Bonjour,

    je possède une BDD MongoDB avec une collection Person. Cette collection contient des utilisateurs possédant des attributs

    je cherche à faire une requête NoSQl donnant le nom de l’entreprise ayant le pourcentage de femmes le plus élevé, ainsi que le pourcentage.

    J'ai essayer pas mal de chose mais sans résultat.

    Si vous avez des idées je suis preneurs
    Images attachées Images attachées  

  2. #2
    Expert Oracle confirmé

    Homme Profil pro
    Consultant Big Data
    Inscrit en
    Mars 2003
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Consultant Big Data
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2003
    Messages : 448
    Points : 926
    Points
    926
    Par défaut
    Rebonjour,

    Je me suis fait ce petit jeu de données avec 9 personnes (5 femmes et 4 hommes) répartis dans 3 sociétés :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    db.Person.insertOne ( { name : "Name1", gender : "Female", company : "A" })
    db.Person.insertOne ( { name : "Name2", gender : "Male",   company : "A" })
     
    db.Person.insertOne ( { name : "Name3", gender : "Female", company : "B" })
    db.Person.insertOne ( { name : "Name4", gender : "Male",   company : "B" })
    db.Person.insertOne ( { name : "Name5", gender : "Male",   company : "B" })
     
    db.Person.insertOne ( { name : "Name6", gender : "Female", company : "C" })
    db.Person.insertOne ( { name : "Name7", gender : "Female", company : "C" })
    db.Person.insertOne ( { name : "Name8", gender : "Female", company : "C" })
    db.Person.insertOne ( { name : "Name9", gender : "Male",   company : "C" })

    Voici ma requête utilisant le Framework d’agrégation de MongoDB :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    db.Person.aggregate([
      {$group:
        {
          _id:"$company",
          nbrFemmes:{$sum: {$cond: {if: {$eq:["$gender","Female"]}, then:1, else:0 } } },
          totalPersonnes:{$sum:1},
        }    
      },
      {$project:
        {
          _id:0,
          company:"$_id",
          percent:{$divide:["$nbrFemmes","$totalPersonnes"]}
        }
      },
      {$sort:{percent:-1}},
      {$limit:1}
    ])
    Et le résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    testgilles @ D427448 > db.Person.aggregate([
    ...   {$group:
    ...     {
    ...       _id:"$company",
    ...       nbrFemmes:{$sum: {$cond: {if: {$eq:["$gender","Female"]}, then:1, else:0 } } },
    ...       totalPersonnes:{$sum:1},
    ...     }
    ...   },
    ...   {$project:
    ...     {
    ...       _id:0,
    ...       company:"$_id",
    ...       percent:{$divide:["$nbrFemmes","$totalPersonnes"]}
    ...     }
    ...   },
    ...   {$sort:{percent:-1}},
    ...   {$limit:1}
    ... ])
    { "company" : "C", "percent" : 0.75 }
    testgilles @ D427448 >



    L'idée est donc d'utiliser l'Aggregation Framework de MongoDB, lequel fonctionne comme un pipeline (on enchaîne les commandes).

    On a ici 4 étapes :

    1) le $group pour faire l'équivalent du Group By en Sql. On regroupe les documents JSON par société, en comptant le nombre de
    femmes ainsi que le nombre total de personnes.

    Le calcul du nombre de femmes est un peu compliqué car il faut décoder le champ Gender : 1 si c'est une femme, 0 pour un homme.
    On utilise donc l'opérateur $cond qui se rapproche du DECODE ou du CASE en Sql.


    2) le $project effectue la projection pour choisir les champs à afficher et on en profite pour calculer le pourcentage en passant, à l'aide de l'opérateur $divide.


    3) le $sort permet de faire le tri sur le champ Pourcentage, dans l'ordre décroissant (-1)


    4) le $limit permet de prendre le premier pourcentage, celui qui est le plus élevé et qui correspond donc au résultat que tu souhaites avoir.

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2017
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2017
    Messages : 6
    Points : 7
    Points
    7
    Par défaut
    Top ! Merci encore Rouardg tu sauve une classe entière

  4. #4
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 565
    Points
    52 565
    Billets dans le blog
    5
    Par défaut
    Permettez moi de vous dire que votre requête est fausse. En effet votre avant dernière ligne...
    {$limit:1}
    ...suppose qu'il n'y aura jamais qu'une seule entreprise ayant cet extremum. Hors il est parfaitement possible que deux entreprises arrivent ex aequo tant sur le nombre de femme que sur l'effectif global ou encore en strict pourcentage.

    Il faut donc, chercher LES maximums de pourcentage et non une ligne !

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  5. #5
    Expert Oracle confirmé

    Homme Profil pro
    Consultant Big Data
    Inscrit en
    Mars 2003
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Consultant Big Data
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2003
    Messages : 448
    Points : 926
    Points
    926
    Par défaut
    Très juste. Merci SQLpro.

    Du coup je rajoute 3 autres sociétés D, E et F, et au total, j'ai les sociétés C, E et F qui ont toutes les trois 75 % de femmes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    db.Person.insertOne ( { name : "Name1",  gender : "Female", company : "A" })
    db.Person.insertOne ( { name : "Name2",  gender : "Male",   company : "A" })
     
    db.Person.insertOne ( { name : "Name3",  gender : "Female", company : "B" })
    db.Person.insertOne ( { name : "Name4",  gender : "Male",   company : "B" })
    db.Person.insertOne ( { name : "Name5",  gender : "Male",   company : "B" })
     
    db.Person.insertOne ( { name : "Name6",  gender : "Female", company : "C" })
    db.Person.insertOne ( { name : "Name7",  gender : "Female", company : "C" })
    db.Person.insertOne ( { name : "Name8",  gender : "Female", company : "C" })
    db.Person.insertOne ( { name : "Name9",  gender : "Male",   company : "C" })
     
    db.Person.insertOne ( { name : "Name10", gender : "Female", company : "D" })
    db.Person.insertOne ( { name : "Name11", gender : "Male",   company : "D" })
    db.Person.insertOne ( { name : "Name12", gender : "Male",   company : "D" })
     
    db.Person.insertOne ( { name : "Name13", gender : "Female", company : "E" })
    db.Person.insertOne ( { name : "Name14", gender : "Female", company : "E" })
    db.Person.insertOne ( { name : "Name15", gender : "Female", company : "E" })
    db.Person.insertOne ( { name : "Name16", gender : "Male",   company : "E" })
     
    db.Person.insertOne ( { name : "Name17", gender : "Female", company : "F" })
    db.Person.insertOne ( { name : "Name18", gender : "Female", company : "F" })
    db.Person.insertOne ( { name : "Name19", gender : "Female", company : "F" })
    db.Person.insertOne ( { name : "Name20", gender : "Male",   company : "F" })

    Ma requête initiale faisait une première agrégation sur chaque société pour connaître le pourcentage de femmes.

    Maintenant on va faire une seconde agrégation sur le pourcentage, en regroupant ensemble dans un tableau les sociétés qui ont le même pourcentage.

    Pour cela, j'utilise l'opérateur $push. Il existe aussi l'opérateur $addToSet qui garantit que chaque élément du tableau est unique, mais je n'en ai pas besoin puisque chaque société est déjà unique.

    Maintenant que l'on a chaque pourcentage de femmes avec la liste des sociétés qui détiennent ce pourcentage, il suffit de reprendre le tri par ordre décroissant sur le pourcentage, et s'arrêter au premier document JSON.

    La requête devient :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    db.Person.aggregate([
      {$group:
        {
          _id:"$company",
          nbrFemmes:{$sum: {$cond: {if: {$eq:["$gender","Female"]}, then:1, else:0 } } },
          totalPersonnes:{$sum:1},
        }    
      },
      {$project:
        {
    	  _id:0,
          company:"$_id",
          percent:{$divide:["$nbrFemmes","$totalPersonnes"]}
        }
      },
      {$group:
        {
    	  _id:"$percent",
    	  companies:{$push:"$company"}
        }    
      },
      {$project:
        {
    	  _id:0,
          percent:"$_id",
          companies:"$companies"
        }
      },
      {$sort:{percent:-1}},
      {$limit:1}
    ])
    Et le résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    >
    > db.Person.aggregate([
    ...   {$group:
    ...     {
    ...       _id:"$company",
    ...       nbrFemmes:{$sum: {$cond: {if: {$eq:["$gender","Female"]}, then:1, else:0 } } },
    ...       totalPersonnes:{$sum:1},
    ...     }
    ...   },
    ...   {$project:
    ...     {
    ...       _id:0,
    ...       company:"$_id",
    ...       percent:{$divide:["$nbrFemmes","$totalPersonnes"]}
    ...     }
    ...   },
    ...   {$group:
    ...     {
    ...       _id:"$percent",
    ...       companies:{$push:"$company"}
    ...     }
    ...   },
    ...   {$project:
    ...     {
    ...       _id:0,
    ...       percent:"$_id",
    ...       companies:"$companies"
    ...     }
    ...   },
    ...   {$sort:{percent:-1}},
    ...   {$limit:1}
    ... ])
    { "percent" : 0.75, "companies" : [ "E", "C", "F" ] }
    >
    >

    PS: il y a certainement d'autres requêtes possibles.

  6. #6
    Expert Oracle confirmé

    Homme Profil pro
    Consultant Big Data
    Inscrit en
    Mars 2003
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Consultant Big Data
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2003
    Messages : 448
    Points : 926
    Points
    926
    Par défaut
    Dernier raffinement : la requête précédente donnait le résultat sous forme d'un pourcentage avec un tableau (Array) de sociétés.

    Si on veut ramener l'affichage au format lignes (autant de documents JSON qu'il y a de sociétés), il faut utiliser l'opérateur $unwind.

    Et on peut encore rajouter pour finir :
    - le renommage du champ companies en companiy
    - un tri sur le nom de la société.

    La requête devient :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    db.Person.aggregate([
      {$group:
        {
          _id:"$company",
          nbrFemmes:{$sum: {$cond: {if: {$eq:["$gender","Female"]}, then:1, else:0 } } },
          totalPersonnes:{$sum:1},
        }    
      },
      {$project:
        {
    	  _id:0,
          company:"$_id",
          percent:{$divide:["$nbrFemmes","$totalPersonnes"]}
        }
      },
      {$group:
        {
    	  _id:"$percent",
    	  companies:{$push:"$company"}
        }    
      },
      {$project:
        {
    	  _id:0,
          percent:"$_id",
          companies:"$companies"
        }
      },
      {$sort:{percent:-1}},
      {$limit:1},
      {$unwind:"$companies"},
      {$project:
        {
          company:"$companies",
    	  percent:"$percent"      
        }
      },
      {$sort:{company:1}}
    ])

    Et le résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    >
    > db.Person.aggregate([
    ...   {$group:
    ...     {
    ...       _id:"$company",
    ...       nbrFemmes:{$sum: {$cond: {if: {$eq:["$gender","Female"]}, then:1, else:0 } } },
    ...       totalPersonnes:{$sum:1},
    ...     }
    ...   },
    ...   {$project:
    ...     {
    ...       _id:0,
    ...       company:"$_id",
    ...       percent:{$divide:["$nbrFemmes","$totalPersonnes"]}
    ...     }
    ...   },
    ...   {$group:
    ...     {
    ...       _id:"$percent",
    ...       companies:{$push:"$company"}
    ...     }
    ...   },
    ...   {$project:
    ...     {
    ...       _id:0,
    ...       percent:"$_id",
    ...       companies:"$companies"
    ...     }
    ...   },
    ...   {$sort:{percent:-1}},
    ...   {$limit:1},
    ...   {$unwind:"$companies"},
    ...   {$project:
    ...     {
    ...       company:"$companies",
    ...       percent:"$percent"
    ...     }
    ...   },
    ...   {$sort:{company:1}}
    ... ])
    { "company" : "C", "percent" : 0.75 }
    { "company" : "E", "percent" : 0.75 }
    { "company" : "F", "percent" : 0.75 }
    >

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 13/02/2017, 09h49
  2. Réponses: 0
    Dernier message: 24/05/2016, 07h52
  3. Réponses: 0
    Dernier message: 29/07/2012, 11h57
  4. Réponses: 0
    Dernier message: 29/07/2012, 11h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo