Вывести несколько элементов из массива с объектами

У меня есть collection:

{
    "_id": {
        "$oid": "5f84ffad51d91fa6247b17e6"
    },
    "chat_id": 1,
    "status": true,
    "members": [{
        "user_id": 2436324243,
        "rank": 1
    }, {
        "user_id": 2346246243,
        "rank": 2
    }, {
        "user_id": 2634243643,
        "rank": 1
    }, {
        "user_id": 2634634234,
        "rank": 0
    }],
    "groups": [...]
},
{
    "_id": {
        "$oid": "5f84ffad51d91fa6247b17e7"
    },
    "chat_id": 2,
    "status": true,
    "members": [{
        "user_id": 1526236,
        "rank": 1
    }, {
        "user_id": 13242664,
        "rank": 2
    }, {
        "user_id": 12315161,
        "rank": 1
    }, {
        "user_id": 21362463,
        "rank": 0
    }],
    "groups": [...]
}

Я хочу получить из chat_id = 2 массив объектов members, там где members.rank >= 1
Ответ должен выглядеть для выше указанных данных так:

{ "members" :  [{  
        "user_id": 1526236,  
        "rank": 1  
    }, {  
        "user_id": 13242664,  
        "rank": 2  
    }, {  
        "user_id": 12315161,  
        "rank": 1  
    }]  
}

Пробовал

db.chats.find({"chat_id": 2, "members": {"$elemMatch": {"rank" : {"$gte": 1}}}}, {"_id": 0, "members.$":1})

Но оно возвращает только один объект


Ответы (1 шт):

Автор решения: Exploding Kitten

У вас несколько ошибок в запросе.

"members.$": 1 вернет первый элемент в найденном массиве, если вы его уберете, то вам будет возвращаться полноценный массив:

"members": [{
    "user_id": 1526236,
    "rank": 1
}, {
    "user_id": 13242664,
    "rank": 2
}, {
    "user_id": 12315161,
    "rank": 1
}, {
    "user_id": 21362463,
    "rank": 0
}],

но тут будет содержаться лишний элемент. Это происходит из-за того, что $elemMatch выбирает те объекты, у который в массиве хотя бы один элемент удовлетворяет условию > 1.

Это можно решить при помощи aggregate, например, так:

db.collection.aggregate(
{
  $match: {
    "chat_id": 2
    // выбираем нужные нам документы
  }
},
{
  $unwind: "$members"
  // выводим каждый элемент массива как отдельный документ
},
{
  $match: {
    "members.rank": {
      "$gte": 1
    }
    // выбирает нужные элементы по rank
  }
},
{
  "$group": {
    "_id": "$_id",
    "members": {
      "$push": "$members"
    }
    // группируем элементы обратно в виде одного массива
  }
})

или так:

db.collection.aggregate(
    {
      $match: {
        "chat_id": 2
      }
    },
    {
      $unwind: "$members"
    },
    {
      $match: {
        "members.rank": {
          "$gte": 1
        }
      }
    },
    {
      $project: {
        _id: 0,
        user_id: "$members.user_id",
        rank: "$members.rank"
      }
    }
)
→ Ссылка