1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    septembre 2009
    Messages
    1 428
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2009
    Messages : 1 428
    Points : 679
    Points
    679

    Par défaut [MongoDB] Recherche une valeur dans plusieurs champs

    Bonjour,

    Dans une collection, j'ai une liste d'objets avec des structures différents.

    J'effectue une première requête pour récupérer que le groupe d'objet qui m’intéresse (ex : type = "voiture").
    Je voudrais affiner ma recherche de manière à ne retourner que les objets dont l'un des champs de l'objet vaut une valeur défini : comment faire ce type de requête ?

    En gros dans ces objets, j'ai des champs dont le nom est de T1 à Tx (qui représentent une liste d'objets enfants) et je voudrais retrouver un des enfant dont je connais la référence :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    obj1 : {
      type : "voiture",
      T1 : "toto",
      // ...
      Tx : "tutu",
    }
    Je voudrais retrouver les objets où l'une des valeurs de T1 à Tx vaut "toto"

    Merci d'avance

  2. #2
    Expert Oracle confirmé

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    mars 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Conseil

    Informations forums :
    Inscription : mars 2003
    Messages : 328
    Points : 618
    Points
    618

    Par défaut

    Bonjour,

    Mon jeu de données :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    db.objects.insertOne ({_id:"obj1", carac:{type:"voiture", t1:"toto", t2:"titi", t3:"tutu"}})
    db.objects.insertOne ({_id:"obj2", carac:{type:"voiture", t1:"tata", t2:"toto", t3:"tutu"}})
    db.objects.insertOne ({_id:"obj3", carac:{type:"voiture", t1:"tete", t2:"titi", t3:"toto"}})
    db.objects.insertOne ({_id:"obj4", carac:{type:"camion", t1:"tete", t2:"titi", t3:"toto"}})
    db.objects.insertOne ({_id:"obj5", carac:{type:"velo"  , t1:"toto", t2:"titi", t3:"toto"}})
    db.objects.insertOne ({_id:"obj6", carac:{type:"voiture", t1:"tete", t2:"titi", t3:"tutu"}})
    db.objects.insertOne ({_id:"obj7", carac:{type:"voiture", t1:"toto", t2:"titi", t3:"toto"}})
    Et la requête avec l'opérateur $or :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    db.objects.find ({"carac.type":"voiture", $or:[ {"carac.t1":"toto"}, {"carac.t2":"toto"}, {"carac.t3":"toto"} ] })

    Le résultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    > db.objects.find ({"carac.type":"voiture", $or:[ {"carac.t1":"toto"}, {"carac.t2":"toto"}, {"carac.t3":"toto"} ] })
    { "_id" : "obj1", "carac" : { "type" : "voiture", "t1" : "toto", "t2" : "titi", "t3" : "tutu" } }
    { "_id" : "obj2", "carac" : { "type" : "voiture", "t1" : "tata", "t2" : "toto", "t3" : "tutu" } }
    { "_id" : "obj3", "carac" : { "type" : "voiture", "t1" : "tete", "t2" : "titi", "t3" : "toto" } }
    { "_id" : "obj7", "carac" : { "type" : "voiture", "t1" : "toto", "t2" : "titi", "t3" : "toto" } }

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    septembre 2009
    Messages
    1 428
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2009
    Messages : 1 428
    Points : 679
    Points
    679

    Par défaut

    Citation Envoyé par rouardg Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    db.objects.find ({"carac.type":"voiture", $or:[ {"carac.t1":"toto"}, {"carac.t2":"toto"}, {"carac.t3":"toto"} ] })
    Le problème de cette méthode est que ton nombre de tx est figé : n'existe t-il pas une méthode pour avoir un nombre variable de tx ?

  4. #4
    Expert Oracle confirmé

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    mars 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Conseil

    Informations forums :
    Inscription : mars 2003
    Messages : 328
    Points : 618
    Points
    618

    Par défaut

    Cela dépasse mes compétences.

    Par contre, cela doit être possible, mais en développant.

    Sous le Shell MongoDB, tu peux développer en Javascript.

    A moins que tu n'utilises un driver MongoDB pour accéder à ta base depuis un applicatif, comme un serveur Web par exemple. Du coup, tu peux aussi développer du code et aller rechercher toutes les clés du document JSON qui sont en tx.

  5. #5
    Expert Oracle confirmé

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    mars 2003
    Messages
    328
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Conseil

    Informations forums :
    Inscription : mars 2003
    Messages : 328
    Points : 618
    Points
    618

    Par défaut

    Bonjour,

    Si tu as un nombre de champs tx variables, alors je les mettrai dans un tableau (Array).

    De plus, comme je ne sais pas comment gérer les noms de ces champs, j'ai transformé ces champs en valeurs.

    Ainsi t1=toto est devenu le document JSON {id:"t1", valeur:"toto"}, histoire d'avoir des champs portant toujours le même nom.

    Je me suis fait ce jeu de données, et pour corser le tout, sur l'objet 3, j'ai mis une valeur toto, mais sur un champ nommé v1, et non pas t1.
    Cet objet ne devrait donc pas être remonté.

    Voici le jeu de données :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    db.objects.drop()
    db.objects.insertOne ({_id:"obj1", type:"voiture", childs: [ {id:"t1", valeur:"toto"}, {id:"t2", valeur:"titi"}, {id:"t3", valeur:"tutu"} ]})
    db.objects.insertOne ({_id:"obj2", type:"voiture", childs: [ {id:"t1", valeur:"tata"}, {id:"t2", valeur:"titi"} ]})
    db.objects.insertOne ({_id:"obj3", type:"voiture", childs: [ {id:"v1", valeur:"toto"}, {id:"t1", valeur:"titi"}, {id:"t2", valeur:"tutu"} ]})
    db.objects.insertOne ({_id:"obj4", type:"voiture", childs: [ {id:"v1", valeur:"tutu"}, {id:"t1", valeur:"titi"}, {id:"t2", valeur:"tutu"}, {id:"t3", valeur:"tete"} ]})
    db.objects.insertOne ({_id:"obj5", type:"camion",  childs: [ {id:"t1", valeur:"toto"}, {id:"t2", valeur:"titi"}, {id:"t3", valeur:"tutu"} ]})
    db.objects.insertOne ({_id:"obj6", type:"voiture", childs: [ {id:"t1", valeur:"toto"}, {id:"t2", valeur:"titi"}, {id:"t3", valeur:"tutu"}, {id:"t4", valeur:"toto"}, {id:"t5", valeur:"tete"} ]})


    Pour la requête, au début j'ai essayé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    db.objects.find ( {"type":"voiture", "childs.id":/^t/, "childs.valeur":"toto"} )
    Mais cela m'a remonté l'objet 3, car d'un côté on trouve toto même si c'est pour v1, et de l'autre on trouve des champs tx :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    > db.objects.find ( {"type":"voiture", "childs.id":/^t/, "childs.valeur":"toto"} )
    { "_id" : "obj1", "type" : "voiture", "childs" : [ { "id" : "t1", "valeur" : "toto" }, { "id" : "t2", "valeur" : "titi" }, { "id" : "t3", "valeur" : "
    tutu" } ] }
    { "_id" : "obj3", "type" : "voiture", "childs" : [ { "id" : "v1", "valeur" : "toto" }, { "id" : "t1", "valeur" : "titi" }, { "id" : "t2", "valeur" : "
    tutu" } ] }
    { "_id" : "obj6", "type" : "voiture", "childs" : [ { "id" : "t1", "valeur" : "toto" }, { "id" : "t2", "valeur" : "titi" }, { "id" : "t3", "valeur" : "
    tutu" }, { "id" : "t4", "valeur" : "toto" }, { "id" : "t5", "valeur" : "tete" } ] }
    >
    Du coup, pas d'autre solution que d'éclater ce tableau à l'aide de l'opérateur $unwind, pour travailler non pas sur la globalité du tableau, mais sur ces éléments, en les prenant 1 par 1.

    Voici la requête d'agrégation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    db.objects.aggregate([
      {$match: {"type":"voiture"}},
      {$unwind: "$childs"},
      {$match: {"childs.id":/^t/, "childs.valeur":"toto"}}
    ])

    Et le résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    > db.objects.aggregate([
    ...   {$match: {"type":"voiture"}},
    ...   {$unwind: "$childs"},
    ...   {$match: {"childs.id":/^t/, "childs.valeur":"toto"}}
    ... ])
    { "_id" : "obj1", "type" : "voiture", "childs" : { "id" : "t1", "valeur" : "toto" } }
    { "_id" : "obj6", "type" : "voiture", "childs" : { "id" : "t1", "valeur" : "toto" } }
    { "_id" : "obj6", "type" : "voiture", "childs" : { "id" : "t4", "valeur" : "toto" } }
    >

    Comme on a éclaté le tableau, l'objet 6 remonte 2 fois, car l'on trouve toto dans les champs t1 et t4.

    Si tu ne veux avoir qu'une seule fois cet objet, il faut faire l'inverse du $unwind, en refaisant un regroupement avec l'opérateur $push :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    db.objects.aggregate([
      {$match: {"type":"voiture"}},
      {$unwind: "$childs"},
      {$match: {"childs.id":/^t/, "childs.valeur":"toto"}},
      {$group:
        {
    	  _id:"$_id",
    	  childs:{$push:"$childs"}
    	}
      }
    ])
    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
    > db.objects.aggregate([
    ...   {$match: {"type":"voiture"}},
    ...   {$unwind: "$childs"},
    ...   {$match: {"childs.id":/^t/, "childs.valeur":"toto"}},
    ...   {$group:
    ...     {
    ...       _id:"$_id",
    ...       childs:{$push:"$childs"}
    ...     }
    ...   }
    ... ])
    { "_id" : "obj6", "childs" : [ { "id" : "t1", "valeur" : "toto" }, { "id" : "t4", "valeur" : "toto" } ] }
    { "_id" : "obj1", "childs" : [ { "id" : "t1", "valeur" : "toto" } ] }
    >

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    septembre 2009
    Messages
    1 428
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2009
    Messages : 1 428
    Points : 679
    Points
    679

    Par défaut

    oki merci beacoup

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 15/11/2011, 23h42
  2. Recherche une valeur dans deux champs
    Par smotte761 dans le forum Langage
    Réponses: 2
    Dernier message: 25/03/2011, 17h13
  3. Recherche d'une valeur dans plusieurs colonnes
    Par Arnaud F. dans le forum Langage SQL
    Réponses: 2
    Dernier message: 01/03/2009, 11h44
  4. copier une valeur dans plusieurs champs
    Par deborah95 dans le forum JavaScript
    Réponses: 0
    Dernier message: 10/02/2009, 16h11
  5. Rechercher une valeur dans plusieurs feuilles
    Par modus57 dans le forum Excel
    Réponses: 28
    Dernier message: 30/03/2008, 18h54

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