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: "reservations@marriott.com" } } ).count()
0
db.messages.find( { 'headers.From': "reservations@marriott.com" }  ).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?

Réponses:


419

db.messages.find( { headers : { From: "reservations@marriott.com" } } )

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


db.messages.find( { 'headers.From': "reservations@marriott.com" } )

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


Documents de notation par points


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'
    }
});

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" : "reservations@marriott.com"
    }
}
{
    "_id" : ObjectId("5cce8eb97d2e7b3fe9c93c33"),
    "headers" : {
        "From" : "reservations@marriott.com",
        "To" : "kprasad.iitd@gmail.com"
    }
}
>

Alors, quel est le résultat de la requête: db.messages.find({headers: {From: "reservations@marriott.com"} }).count()

Il doit en être un car ces requêtes de documents sont headerségales à l'objet {From: "reservations@marriott.com"}, 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: "kprasad.iitd@gmail.com", From: "reservations@marriott.com"}  }).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: "reservations@marriott.com", To: "kprasad.iitd@gmail.com"}  }).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': "reservations@marriott.com" }  ).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 .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.