#mongodb #sum #aggregate #nested-object
#mongodb #сумма #агрегировать #вложенный объект
Вопрос:
Я пытаюсь суммировать (расходы по месяцам / годам) коллекции с вложенными суммами — безуспешно.
Это коллекция (извлечение):
[
{
"_id" : ObjectId("5faaf88d0657287993e541a5"),
"segment" : {
"l1" : "Segment A",
"l2" : "001"
},
"invoiceNo" : "2020.10283940",
"invoicePos" : 3,
"date" : ISODate("2019-09-06T00:00:00.000Z"),
"amount" : {
"document" : {
"amount" : NumberDecimal("125.000000000000"),
"currCode" : "USD"
},
"local" : {
"amount" : NumberDecimal("123.800000000000"),
"currCode" : "CHF"
},
"global" : {
"amount" : NumberDecimal("123.800000000000"),
"currCode" : "CHF"
}
}
},
...
]
Я хотел бы суммировать совокупный объем счетов-фактур за месяц в «глобальной» валюте.
Я попробовал этот запрос на MongoDB:
db.invoices.aggregate(
{$project : {
month : {$month : "$date"},
year : {$year : "$date"},
amount : 1
}},
{$unwind: '$amount'},
{$group : {
_id : {month : "$month" ,year : "$year" },
total : {$sum : "$amount.global.amount"}
}})
В результате я получаю следующее:
/* 1 */
{
"_id" : ObjectId("5faaf88d0657287993e541a5"),
"amount" : {
"document" : {
"amount" : NumberDecimal("125.000000000000"),
"currCode" : "USD"
},
"local" : {
"amount" : NumberDecimal("123.800000000000"),
"currCode" : "CHF"
},
"global" : {
"amount" : NumberDecimal("123.800000000000"),
"currCode" : "CHF"
}
},
"month" : 9,
"year" : 2019
}
/* 2 */
{
"_id" : ObjectId("5faaf88d0657287993e541ac"),
"amount" : {
"document" : {
"amount" : NumberDecimal("105.560000000000"),
"currCode" : "CHF"
},
"local" : {
"amount" : NumberDecimal("105.560000000000"),
"currCode" : "CHF"
},
"global" : {
"amount" : NumberDecimal("105.560000000000"),
"currCode" : "CHF"
}
},
"month" : 11,
"year" : 2020
}
Однако это не суммирует все счета-фактуры за месяц, а выглядит как отдельные строки счета-фактуры — без агрегирования.
Я хотел бы получить такой результат:
[
{
"month": 11,
"year": 2020,
"amount" : NumberDecimal("99999.99")
},
{
"month": 10,
"year": 2020,
"amount" : NumberDecimal("99999.99")
},
{
"month": 9,
"year": 2020,
"amount" : NumberDecimal("99999.99")
}
]
Что не так с моим запросом?
Ответ №1:
Будет ли это полезно?
db.invoices.aggregate([
{
$group: {
_id: {
month: {
$month: "$date"
},
year: {
$year: "$date"
}
},
total: {
$sum: "$amount.global.amount"
}
}
},
{$sort:{"_id.year":-1, "_id.month":-1}}
])
Если вам нужно какое-либо дополнительное объяснение, дайте мне знать, но код довольно короткий и понятный.
Комментарии:
1. Отлично, это работает! Однако при более чем 500 тыс. записей этот метод не выполняет задачу в течение 30 секунд. Есть ли другой способ выполнить запрос?
2. Вы можете попробовать {$limit:<number>} в качестве этапа после $sort затем, после того, как он найдет лучшие документы, он перестанет искать больше @Herdy
Ответ №2:
В принципе, ваш конвейер агрегации в порядке, есть несколько ошибок:
- Конвейер агрегации ожидает массив
$unwind
бесполезно, потому$amount
что не является массивом. Один элемент в -> один документ- Вы можете использовать функцию даты напрямую
Итак, коротко и просто:
db.invoices.aggregate([
{
$group: {
_id: { month: { $month: "$date" }, year: { $year: "$date" } },
total: { $sum: "$amount.global.amount" }
}
}
])