【问题标题】:Mongoose SUM get stackedMongoose SUM 被堆叠
【发布时间】:2020-02-07 20:25:38
【问题描述】:

我正在尝试在 mongoDB 上进行简单的 SUM 以计算单个客户端的价格数量。

我的收藏:

{"_id":"5d973c71dd93adfbda4c7272","name":"Faktura2019006","clientId":"5d9c87a6b9676069c8b5e15b","expiration":"2019-10-02T01:11:18.965Z","price":999999,"userId":"123"},
{"_id":"5d9e07e0b9676069c8b5e15d","name":"Faktura2019007","clientId":"5d9c87a6b9676069c8b5e15b","expiration":"2019-10-02T01:11:18.965Z","price":888,"userId":"123"}

我尝试了什么:

// invoice.model.js
const mongoose = require("mongoose");

const InvoiceSchema = mongoose.Schema({
  _id: String,
  name: String,
  client: String,
  userId: String,
  expiration: Date,
  price: Number
});

module.exports = mongoose.model("Invoice", InvoiceSchema, "invoice");

// invoice.controller.js
const Invoice = require("../models/invoice.model.js");

exports.income = (req, res) => {
  console.log("Counting Income");

  Invoice.aggregate([
    {
      $match: {
        userId: "123"
      }
    },
    {
      $group: {
        total: { $sum: ["$price"] }
      }
    }
  ]);
};

会发生什么:

当我现在打开浏览器并调用上面的代码时,我会在终端中看到控制台日志“计算收入”,但在浏览器中它只是永远加载,没有任何反应。

很可能我只是错过了一些愚蠢的小事,但我试图找出它很长一段时间没有任何成功,所以欢迎任何建议。

【问题讨论】:

  • 你没有从控制器返回任何东西(从控制器发送 res),这就是为什么 api 根本没有返回任何东西
  • 这不是关于不返回,而是继续加载:) 所以我的问题不是我没有得到响应,问题是获取永远不会结束
  • 将组更改为 {$group:{_id:null,total:{$sum:"$price"}}} 然后尝试
  • @sushantmehta 没有任何改变

标签: node.js mongodb express mongoose nosql


【解决方案1】:

控制器永远不会结束的原因是因为你没有结束响应过程(意思是,你需要使用res对象并将一些东西发回给调用者)。

为了获取聚合值,还需要执行管道(见this example)。

另外,正如 cmets 中有人指出的那样,您需要在您的组中添加 _id: null 以指定您不会按任何特定字段进行分组(请参阅second example here)。

最后,在$sum 运算符中,您只需要删除数组括号,因为您只想对单个字段求和(请参阅a few examples down here)。

这里是修改后的代码:

// 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);
  });
};

编辑您对何时返回空数组的评论。

如果你想总是返回相同类型的对象,我会在控制器中控制它。我不确定是否有一种奇特的方法可以使用 mongo 中的聚合管道来执行此操作,但这是我会做的。

 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]);
    }
  });

在这里,如果你找到123 中的userId,那么你会得到这个作为回报:

{
    "total": 1000887
}

但是,如果您将 userId 更改为 1123,这在您的数据库中不存在,结果将是:

{
    "total": 0
}

这样,您的客户端始终可以使用相同类型的对象。

另外,我将$project 管道阶段放在那里的原因是为了抑制_id 字段(请参阅here for more info)。

【讨论】:

  • 谢谢@Joseph,你是对的。我能再问一件事吗?现在,如果它不匹配任何内容,它将返回空对象。我可以更改它以使其成为总值为 0 的相同对象吗?
  • @Andurit 很高兴为您提供帮助!当然,请查看答案中的新编辑。我希望这会有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-30
  • 1970-01-01
  • 2016-02-17
  • 2018-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多