Como consultar objetos aninhados?

204

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

db.messages.find( { headers : { From: "[email protected]" } } ).count()
0
db.messages.find( { 'headers.From': "[email protected]" }  ).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?

Edmondo1984
fonte

Respostas:

419

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

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


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

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


Documentos de notação de ponto

shx2
fonte
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'
    }
});
Edmondo1984
fonte
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" : "[email protected]"
    }
}
{
    "_id" : ObjectId("5cce8eb97d2e7b3fe9c93c33"),
    "headers" : {
        "From" : "[email protected]",
        "To" : "[email protected]"
    }
}
>

Então, qual é o resultado da consulta: db.messages.find({headers: {From: "[email protected]"} }).count()

Deve ser uma porque essas consultas para documentos são headersiguais ao objeto {From: "[email protected]"}, 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: "[email protected]", From: "[email protected]"}  }).count()
0

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

> db.messages.find({headers: {From: "[email protected]", To: "[email protected]"}  }).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': "[email protected]" }  ).count()
2

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

Krishna Prasad
fonte