Mongoose SUM 被堆叠

Posted

技术标签:

【中文标题】Mongoose SUM 被堆叠【英文标题】:Mongoose SUM get stacked 【发布时间】: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 没有任何改变 【参考方案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 很高兴为您提供帮助!当然,请查看答案中的新编辑。我希望这会有所帮助。

以上是关于Mongoose SUM 被堆叠的主要内容,如果未能解决你的问题,请参考以下文章

子文档中行的 Mongoose 聚合“$sum”

mongoDB,带有 $sum 和 $count 的 mongoose 聚合查询

mongoDB,带有 $sum 和 $count 的 mongoose 聚合查询

Node.js/Mongoose/MongoDb Typescript MapReduce - emit() 和 Array.sum() 方法

Node.js/Mongoose/MongoDb Typescript MapReduce - emit() 和 Array.sum() 方法

无法操纵 mongoose 查询结果 - 承诺未定义