Причина, по которой контроллер никогда не завершает свою работу, заключается в том, что вы не заканчиваете процесс ответа (то есть вам нужно использовать объект res
и отправить что-то обратно вызывающей стороне).
Для того, чтобы получитьсовокупное значение, вам также необходимо выполнить конвейер (см. этот пример ).
Также, как кто-то указал в комментариях, вам нужно добавить _id: null
в вашей группе кукажите, что вы не собираетесь группировать по какому-либо конкретному полю (см. второй пример здесь ).
Наконец, в операторе $sum
то, что вы пытаетесь сделать,вам просто нужно снять скобки массива, так как вы хотите суммировать только по одному полю (см. несколько примеров здесь ).
Вот модифицированный код:
// invoice.controller.js
const Invoice = require("../models/invoice.model.js");
exports.income = (req, res) => {
console.log("Counting Income");
Invoice.aggregate([
{
$match: {
userId: "123"
}
},
{
$group: {
_id: null,
total: { $sum: "$price" }
}
}
]).then((response) => {
res.json(response);
});
};
Правка для вашего комментария о том, когда возвращается пустой массив.
Если вы хотите всегда возвращать один и тот же тип объекта, я бы управлял этим в контроллере. Я не уверен, есть ли причудливый способ сделать это с агрегатным конвейером в монго, но это то, что я бы сделал.
Invoice.aggregate([
{
$match: {
userId: "123"
}
},
{
$group: {
_id: null,
total: { $sum: "$price" }
}
},
{
$project: {
_id: 0,
total: "$total"
}
}
]).then((response) => {
if (response.length === 0) {
res.json({ total: 0 });
} else {
// always return the first (and only) value
res.json(response[0]);
}
});
Здесь, если вы найдете userId
из 123
, тогда вы получите это как возвращаемое значение:
{
"total": 1000887
}
Но если вы измените userId
, скажем, на 1123
, которого нет в вашей БД, результат будет:
{
"total": 0
}
Таким образом, ваш клиент всегда может использовать один и тот же тип объекта.
Кроме того, причина, по которой я включил этап конвейера $project
, заключалась в подавлении поля _id
(см. здесь для получения дополнительной информации ).