Comment interroger des objets imbriqués?

205

J'ai un problème lors de l'interrogation de mongoDB avec la notation d'objets imbriqués:

db.messages.find( { headers : { From: "[email protected]" } } ).count()
0
db.messages.find( { 'headers.From': "[email protected]" }  ).count()
5

Je ne vois pas ce que je fais mal. Je m'attends à ce que la notation d'objet imbriqué renvoie le même résultat que la requête de notation par points. Où ai-je tort?

Edmondo1984
la source

Réponses:

419

db.messages.find( { headers : { From: "[email protected]" } } )

Cette recherche les documents où headers est égal { From: ... } , c'est-à-dire ne contient aucun autre champ.


db.messages.find( { 'headers.From': "[email protected]" } )

Cela ne regarde que le headers.Fromchamp, non affecté par les autres champs contenus ou manquants dans headers.


Documents de notation par points

shx2
la source
Est-il possible de le faire sans les guillemets autour de "headers.From"?
trysis
Je ne sais pas, je me demandais juste, et j'ai pensé que cela pouvait parfois être utile.
trysis
3
@trysis - En pratique, j'ai trouvé que déclarer des objets en ligne (comme les exemples dans les documents mongo [ose], et dans la plupart des exemples) n'est tout simplement pas suffisant dans le monde réel. J'ai développé l'habitude de créer des objets 'conditions' et 'champs' sur lesquels je peux faire des trucs comme conditions['some.path'] = 'value'dans ma logique métier, puis lancer une seule requête à la fin:find(conditions, fields, callback);
Ryan Wheale
Et si ce let disent que j'ai une clé qui contient « domain.com », cela ne fonctionnera pas: domains.domain.com. Existe-t-il une solution de contournement pour ce scénario (sans modifier le domaine.com par autre chose, par exemple domain_com)?
Rens Tillmann
1
Répondant à mon propre commentaire, il est préférable d'éviter d'utiliser complètement des points dans vos clés. Dans ma solution, j'ai complètement abandonné les domaines étant des clés et créé une tranche / tableau à la place.
Rens Tillmann
20

Les deux mécanismes de requête fonctionnent de différentes manières, comme suggéré dans les documents de la section Sous - documents :

Lorsque le champ contient un document incorporé (c'est-à-dire un sous - document ), vous pouvez soit spécifier le sous-document entier comme valeur d'un champ, soit «atteindre» le sous - document à l' aide de la notation par points, pour spécifier les valeurs des champs individuels du sous - document :

Les correspondances d'égalité dans les sous-documents sélectionnent les documents si le sous-document correspond exactement au sous-document spécifié, y compris l'ordre des champs.


Dans l'exemple suivant, la requête correspond à tous les documents dans lesquels la valeur du producteur de champs est un sous-document qui contient uniquement le champ companyavec la valeur 'ABC123'et le champ addressavec la valeur '123 Street', dans l'ordre exact:

db.inventory.find( {
    producer: {
        company: 'ABC123',
        address: '123 Street'
    }
});
Edmondo1984
la source
8
J'étais devenu fou. Cela me semble assez incohérent, car lors de la requête d'objets, ses propriétés directes peuvent être mises en correspondance dans n'importe quel ordre.
Capaj
7

Puisqu'il y a beaucoup de confusion sur les requêtes de collecte MongoDB avec des sous-documents , j'ai pensé qu'il valait la peine d'expliquer les réponses ci-dessus avec des exemples:

D'abord, je n'ai inséré que deux objets dans la collection à savoir: messagecomme:

> db.messages.find().pretty()
{
    "_id" : ObjectId("5cce8e417d2e7b3fe9c93c32"),
    "headers" : {
        "From" : "[email protected]"
    }
}
{
    "_id" : ObjectId("5cce8eb97d2e7b3fe9c93c33"),
    "headers" : {
        "From" : "[email protected]",
        "To" : "[email protected]"
    }
}
>

Alors, quel est le résultat de la requête: db.messages.find({headers: {From: "[email protected]"} }).count()

Il doit en être un car ces requêtes de documents sont headerségales à l'objet {From: "[email protected]"}, c'est-à-dire qu'elles ne contiennent aucun autre champ ou nous devons spécifier le sous-document entier comme valeur d'un champ.

Donc, selon la réponse de @ Edmondo1984

L'égalité correspond dans les sous-documents sélectionnez les documents si le sous-document correspond exactement au sous-document spécifié, y compris l'ordre des champs .

D'après les instructions ci-dessus, quel devrait être le résultat de la requête ci-dessous?

> db.messages.find({headers: {To: "[email protected]", From: "[email protected]"}  }).count()
0

Et si nous modifions l'ordre des sous-documents des deuxièmes documents, c'est-à From- Todire les mêmes?

> db.messages.find({headers: {From: "[email protected]", To: "[email protected]"}  }).count()
1

ainsi, il correspond exactement au sous-document spécifié, y compris l'ordre des champs .

Pour l'utilisation de l'opérateur point, je pense que c'est très clair pour tout le monde. Voyons le résultat de la requête ci-dessous:

> db.messages.find( { 'headers.From': "[email protected]" }  ).count()
2

J'espère que ces explications avec l'exemple ci-dessus rendront quelqu'un plus clair sur la recherche de requête avec des sous-documents .

krishna Prasad
la source