Есть ли способ вернуть определенные вложенные поля из запроса в MongoDB?

Есть ли способ получить сумму денег, выплаченную в зависимости от категории спорта? Это не может быть ограничено только "Джоном", но во всех документах коллекции.

Ожидаемый запрос возврата для предоставленных данных:

{
  {"Fight":   [100,95] },
  {"Running": [50]     }
}

Пример данных:

{"_id":"5z621578b0ce483b9866fb1f",
 "Name":"John",
 "Sports":[
           {"Category":"Fight",
            "Billing":[
                       {"Month":"Jan",
                        "Status":"Paid",
                        "Price":100},
                      {"Month":"Feb",
                       "Status":"Not Paid",
                       "Price":125}, 
                      {"Month":"Mar",
                       "Status":"Paid",
                       "Price":95}      
                      ]
           },

          {"Category":"Running",
           "Billing":[
                      {"Month":"Jan",
                       "Status":"Not Paid",
                       "Price":200}, 
                      {"Month":"Feb",
                       "Status":"Paid",
                       "Price":50}  
                     ]
          }
      ]
}

Другими словами: мне нужно сравнить статус биллинга внутри каждого вложенного объекта и проверить, является ли он "Оплаченным", а затем, если true, добавить соответствующий объект биллинга "Цена" в соответствующий массив " Вид спорта".

Для всех документов в коллекции, с несколькими спортивными категориями и несколькими месяцами выставления счетов. Но всегда одна и та же вложенная структура.

Заранее спасибо!

1 ответ

Решение

Как сказал Уиллис в своем комментарии, вы можете использовать агрегацию: https://docs.mongodb.com/manual/aggregation/


Следующая агрегация даст вам данные, которые вы ищете (замените счета фактическим названием вашей коллекции):

db.billings.aggregate([
    { $unwind: '$Sports'},
    { $unwind: '$Sports.Billing'},
    { $match: { 'Sports.Billing.Status': 'Paid' } },
    {
        $group: {
            _id: '$Sports.Category',
            Category: {$first: '$Sports.Category'},
            Prices: { $push: '$Sports.Billing.Price' }
        }
    },
    { $project: {_id: 0} }
]);

Результат этой агрегации будет выглядеть примерно так:

[
    {
        "Category" : "Running",
        "Prices" : [ 
            50.0
        ]
    },
    {
        "Category" : "Fight",
        "Prices" : [ 
            100.0, 
            95.0
        ]
    }
]

Точный формат, который вы запросили в своем вопросе, немного ненормальный; на мой взгляд, я думаю, что было бы лучше сохранить его в форме агрегации выше результатов. Но если вы хотите получить такую ​​форму, как в вопросе, агрегация будет немного более сложной:

db.billings.aggregate([
    { $unwind: '$Sports'},
    { $unwind: '$Sports.Billing'},
    { $match: { 'Sports.Billing.Status': 'Paid' } },
    {
        $group: {
            _id: '$Sports.Category',
            Prices: { $push: '$Sports.Billing.Price' }
        }
    },
    {
        $group: {
            _id: 0,
            Sports: { $push: { Category: '$_id', Prices: '$Prices' } }
        }
    },
    {
        $project: {
            Sports: {
                $arrayToObject: {
                    '$map': {
                        'input': '$Sports',
                        'as': 'el',
                        'in': {
                            'k': '$$el.Category',
                            'v': '$$el.Prices'
                        }
                    }
                }
            }
        }
    },
    { $replaceRoot: { newRoot: '$Sports'} }
]);
Другие вопросы по тегам