Как выполнить запрос к полям массива объектов в mongodb? - PullRequest
0 голосов
/ 27 октября 2019

У меня есть коллекция монго со следующим документом:

{
    _id: ObjectId("5c7ba3c0e30e6132f8b0c4ef"),
    replies: [
        {
            _id: ObjectId("5c7ba3c0e30e6132f8b0c4ef"),
            status: 'rejected'
        }
    ]
}

Я хочу получить все ответы с утвержденным статусом, поэтому я делаю следующий запрос:

Collection.find({'replies.status': 'approved'})

и ещедокумент выше появляется в результатах. Что я делаю не так?

1 Ответ

2 голосов
/ 27 октября 2019

Это распространенное недоразумение процесса запроса. Я подозреваю, что один из ваших документов выглядит следующим образом:

{
    "_id" : 0,
  "replies" : [
  { "_id" : "R0", status: "rejected"}
  ,{ "_id" : "R1", status: "approved"}
  ]
}

Проблема заключается в том, что выполнение find для массива будет соответствовать любому документу, где, по крайней мере, совпадает одна из записей массива;это НЕ фильтрует результат, чтобы ПРОСТО эти записи. Вот два подхода. С учетом этих настроек данных:

var r =
[
{
    "_id" : 0,
  "replies" : [
  { "_id" : "R0", status: "rejected"}
  ,{ "_id" : "R1", status: "approved"}
  ]
}
,{
    "_id" : 1,
  "replies" : [
  { "_id" : "R2", status: "rejected"}
  ,{ "_id" : "R3", status: "rejected"}
  ]
}
,{
    "_id" : 2,
  "replies" : [
  { "_id" : "R4", status: "rejected"}
  ,{ "_id" : "R5", status: "approved"}
  ]
}
 ];

Подход 1: Простой, а встроенный массив мал (десятки, а не 100 или 1000 записей.

db.foo.aggregate([
// This will find all docs where ANY of the replies array has AT LEAST ONE      
// entry "approved."   It will NOT filter just those.                           
{$match: {"replies.status": "approved"}}

// Now that we have them, unwind and "refilter"                                 
,{$unwind: "$replies"}

,{$match: {"replies.status": "approved"}}
   ]);

{ "_id" : 0, "replies" : { "_id" : "R1", "status" : "approved" } }
{ "_id" : 2, "replies" : { "_id" : "R5", "status" : "approved" } }

Подход 2: Используйте $filter, еслимассив очень большой и использование $unwind создает тысячи документов. Этот подход также полезен для сохранения структуры исходного документа:

db.foo.aggregate([
// This will find all docs where ANY of the replies array has AT LEAST ONE      
// entry "approved."   It will NOT filter just those.                           
{$match: {"replies.status": "approved"}}

// To avoid $unwind, directly filter just "approved" and reset the replies      
// field back into the parent doc:                                              
,{$addFields: {replies: {$filter: {
                input: "$replies",
                as: "zz",
                cond: { $eq: [ "$$zz.status", "approved" ] }
            }}
    }}

   ]);

/*                                                                              
{                                                                               
    "_id" : 0,                                                                  
        "replies" : [                                                           
                     {                                                          
                         "_id" : "R1",                                          
                             "status" : "approved"                              
                             }                                                  
                     ]                                                          
        }                                                                       
{                                                                               
    "_id" : 2,                                                                  
        "replies" : [                                                           
                     {                                                          
                         "_id" : "R5",                                          
                             "status" : "approved"                              
                             }                                                  
                     ]                                                          
        }                                                                       
}        
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...