Как запросить вложенные объекты?

205

У меня проблема при запросе mongoDB с обозначением вложенных объектов:

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

Я не вижу, что я делаю неправильно. Я ожидаю, что нотация вложенных объектов вернет тот же результат, что и запрос точечной нотации. Где я не прав?

Edmondo1984
источник

Ответы:

419

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

Этот запрос для документов, где headers равно { From: ... } , то есть не содержит других полей.


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

Это только смотрит на headers.Fromполе, не затронутое другими полями, содержащимися или отсутствующими в headers.


Dot-обозначения документов

shx2
источник
Есть ли способ сделать это без кавычек вокруг "заголовки. От"?
trysis
Я не знаю, просто интересно, и подумал, что иногда это может быть полезно.
trysis
3
@trysis - На практике я обнаружил, что объявления встроенных объектов (например, примеров в документах mongo [ose] и в большинстве примеров) просто недостаточно в реальном мире. У меня выработалась привычка создавать объекты «условия» и «поля», на которых я могу делать что-то вроде conditions['some.path'] = 'value'своей бизнес-логики, а затем выполнить один запрос в конце:find(conditions, fields, callback);
Райан Уил
Что делать , если , скажем , у меня есть ключ , который содержит «domain.com», это не будет работать: domains.domain.com. Есть ли обходной путь для этого сценария (без изменения domain.com на что-то другое, например, domain_com)?
Ренс Тиллманн
1
Отвечая на мой собственный комментарий, лучше всего избегать использования точек в ваших ключах. В моем решении я полностью исключил домены, являющиеся ключами, и вместо этого создал срез / массив.
Ренс Тильманн
20

Механизм двух запросов работает по-разному, как предлагается в документации в разделе Поддокументы :

Если поле имеет встроенный документ (т.е. целого документ ), вы можете либо указать весь поддокумент в качестве значения поля, или «Достать в» в поддокумент , используя точечную нотацию, чтобы указать значения для отдельных полей в поддокументе :

Равенство совпадает в вложенных документах, выбирают документы, если вложенный документ точно соответствует указанному вложенному документу, включая порядок полей.


В следующем примере запрос сопоставляет все документы, в которых значение источника поля является вложенным документом, содержащим только поле companyсо значением 'ABC123'и поле addressсо значением '123 Street'в точном порядке:

db.inventory.find( {
    producer: {
        company: 'ABC123',
        address: '123 Street'
    }
});
Edmondo1984
источник
8
Я сходил с ума. Это кажется мне довольно противоречивым, потому что при запросе объектов его прямые свойства могут быть сопоставлены в любом порядке.
Капай
7

Поскольку существует большая путаница в запросах коллекции MongoDB с поддокументами , я подумал, что стоит объяснить приведенные выше ответы примерами:

Сначала я вставил только два объекта в коллекцию, а именно: messageкак:

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

Итак, каков результат запроса: db.messages.find({headers: {From: "reservations@marriott.com"} }).count()

Это должен быть один, потому что эти запросы для документов headersравны объекту {From: "reservations@marriott.com"}, т. Е. Не содержат других полей, или мы должны указать весь поддокумент в качестве значения поля.

Так что согласно ответу от @ Edmondo1984

Равенство совпадений внутри вложенных документов выбирает документы, если вложенный документ точно соответствует указанному вложенному документу, включая порядок полей .

Из приведенных выше утверждений, каков должен быть результат запроса ниже?

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

А что, если мы изменим порядок Fromи Toт. Е. Такие же, как субдокументы вторых документов?

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

таким образом, он точно соответствует указанному поддокументу, включая порядок полей .

Для использования точечного оператора, я думаю, это очень ясно для каждого. Давайте посмотрим на результат запроса ниже:

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

Я надеюсь, что эти объяснения с приведенным выше примером сделают кого-то более ясным при поиске запроса с поддокументами .

Кришна Прасад
источник