Como consultar objetos aninhados?


204

Eu tenho um problema ao consultar o mongoDB com notação de objetos aninhados:

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

Não vejo o que estou fazendo de errado. Espero que a notação de objeto aninhado retorne o mesmo resultado que a consulta de notação de ponto. Onde eu estou errado?

Respostas:


419

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

Isso consulta documentos onde headers é igual a { From: ... } , ou seja, não contém outros campos.


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

Isso examina apenas o headers.Fromcampo, não afetado por outros campos contidos ou ausentes de headers.


Documentos de notação de ponto


Existe alguma maneira de fazer isso sem as aspas em torno de "headers.From"?
— trysis

Eu não sei, apenas pensando, e pensei que às vezes pode ser útil.
— trysis

3
@trysis - Na prática, descobri que declarar objetos embutidos (como os exemplos nos mongo [ose] docs e na maioria dos exemplos por aí) simplesmente não é suficiente no mundo real. Eu desenvolvi o hábito de criar objetos 'conditions' e 'fields' nos quais eu posso fazer coisas como conditions['some.path'] = 'value'na minha lógica de negócios e, em seguida, executar uma única consulta no final:find(conditions, fields, callback);
— Ryan Wheale

E se deixou-nos dizer que tenho uma chave que contém "domain.com", isso não vai funcionar: domains.domain.com. Existe alguma solução alternativa para esse cenário (sem alterar o domain.com para outra coisa, por exemplo, domain_com)?
— Rens Tillmann

1
Respondendo ao meu próprio comentário, é melhor evitar usar pontos completamente em suas teclas. Na minha solução, abandonei completamente os domínios como chaves e, em vez disso, criei uma fatia / matriz.
— Rens Tillmann 11/06

20

O mecanismo de duas consultas funciona de maneiras diferentes, conforme sugerido nos documentos na seção Subdocumentos :

Quando o campo contém um documento incorporado (ou seja, subdocumento ), você pode especificar todo o subdocumento como o valor de um campo ou "acessar" o subdocumento usando a notação de ponto, para especificar valores para campos individuais no subdocumento :

Correspondências de igualdade nos subdocumentos selecionam documentos se o subdocumento corresponder exatamente ao subdocumento especificado, incluindo a ordem dos campos.


No exemplo a seguir, a consulta corresponde a todos os documentos em que o valor do produtor do campo é um subdocumento que contém apenas o campo companycom o valor'ABC123' e o campo addresscom o valor '123 Street', na ordem exata:

db.inventory.find( {
    producer: {
        company: 'ABC123',
        address: '123 Street'
    }
});

8
Eu estava ficando louco. Isso me parece bastante inconsistente, porque, ao consultar objetos, suas propriedades diretas podem ser correspondidas em qualquer ordem.
— 11789 Capajd

7

Como há muita confusão sobre as consultas da coleção MongoDB com sub-documentos , achei que vale a pena explicar as respostas acima com exemplos:

Primeiro, inseri apenas dois objetos na coleção, a saber: messagecomo:

> 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"
    }
}
>

Então, qual é o resultado da consulta: db.messages.find({headers: {From: "reservations@marriott.com"} }).count()

Deve ser uma porque essas consultas para documentos são headersiguais ao objeto {From: "reservations@marriott.com"}, apenas, por exemplo, não contém outros campos ou devemos especificar todo o sub-documento como o valor de um campo.

Então, de acordo com a resposta de @ Edmondo1984

Correspondências de igualdade nos sub-documentos selecionam documentos se o subdocumento corresponder exatamente ao sub-documento especificado, incluindo a ordem dos campos .

A partir das instruções acima, qual deve ser o resultado da consulta abaixo?

> db.messages.find({headers: {To: "kprasad.iitd@gmail.com", From: "reservations@marriott.com"}  }).count()
0

E se mudarmos a ordem Frome, por exemplo, o Tomesmo que os sub-documentos dos segundos documentos?

> db.messages.find({headers: {From: "reservations@marriott.com", To: "kprasad.iitd@gmail.com"}  }).count()
1

portanto, corresponde exatamente ao sub-documento especificado, incluindo a ordem dos campos .

Para usar o operador de ponto, acho que é muito claro para todos. Vamos ver o resultado da consulta abaixo:

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

Espero que essas explicações com o exemplo acima tornem alguém mais claro sobre a consulta de busca com sub-documentos .

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.