【问题标题】:Mongoose aggregate $sum returning zeroMongoose 聚合 $sum 返回零
【发布时间】:2016-02-17 16:34:42
【问题描述】:

我有一个这样的聚合函数:

var match = {};
match["products.totalprice"] = {$exists:true};

var project = {};
    project["_id"] = 0
    project["products.totalprice"] = 1;
    project["line"] = "$products.closedate";

ThisCollection.aggregate([
    {$match: match},
    {$project: project},
    {$group: {
        _id: "$line",
        total: {$sum: {$ifNull: ["$products.totalprice", 0]}}
    }}

], function(err, docs){
    console.log(docs);
});

我的模式本质上是一个名称和 _id 字段,其中包含一个嵌套的产品数组,其中包含总价格、关闭日期和其他一些字段:

db.data.save({name:"a",products:{totalprice:1,closedate:1,...}})
db.data.save({name:"b",products:{totalprice:2,closedate:2,...}})

架构看起来像:

var Products = new Schema({
    totalprice: Number,
    closedate: Date,
    otherRandomFields: ...
}) 

var ThisCollection = new Schema({
    name: String, 
    products:[Products]
});

docs 正在返回我希望看到的日期对象,但总数始终为 0。

我正在检查$exists$ifNull,因为我在某处看到了建议(但现在似乎找不到)。我还确认 products.totalprice 在我的架构中属于 Number 类型。

是否有任何人认为不正确?

编辑

运行此函数的实际(部分)输出:

0: {_id: ["2014-01-01T05:00:00.000Z"], total: 0}
1: {_id: ["2014-01-31T05:00:00.000Z"], total: 0}
2: {_id: ["2014-02-01T05:00:00.000Z"], total: 0}

_id 返回一个数组很奇怪吗?

更多信息

认为这可能是$sum 的问题,因此尝试了一些其他方法,例如$first$push - 这是$push 的输出:

0: {_id: "2014-01-01T05:00:00.000Z", total: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]}
1: {_id: "2014-01-31T05:00:00.000Z", total: [0, 0, 0]}
2: {_id: "2014-02-01T05:00:00.000Z", total: [0, 0, 0, 0, 0, 0, 0]}

【问题讨论】:

  • 如果您可以编辑您的问题以包含一些示例文档和聚合的预期输出,那将非常有帮助。
  • @chridam 我添加了一些细节。我存储了数十万个实际文档。我希望看到_id 被聚合为products.closedatetotal 应该是每个products.closedateproducts.totalprice 的总和。
  • @chridam 我将_id 字段作为预期的products.closedate,但相应的total 字段始终返回0
  • 这行match["product.totalprice"] = {$exists:true};不应该是match["products.totalprice"] = {$exists:true};吗?
  • @chridam 已修复。 (我的实际函数是动态生成的,我的代码要长得多,我试图在这个例子中尽可能真实)

标签: node.js mongodb mongoose aggregation-framework


【解决方案1】:

尝试以下聚合管道,它从您的日期中提取 $year$month$dayOfMonth,然后使用那些作为组的键。此外,检查字段是否存在并为其分配值的逻辑最好在 $project 管道中完成,因为这使您可以轻松调试管道操作并且代码可读:

var match = {};
match["products.totalprice"] = {$exists:true};

var project = {};
    project["_id"] = 0;        
    project["line"] = {
        "year": { "$year": "$products.closedate" },
        "month": { "$month": "$products.closedate" },
        "day": { "$dayOfMonth": "$products.closedate" }
    };
    project["total"] = {
        "$ifNull": [ "$products.totalprice", 0 ]
    }

ThisCollection.aggregate([
    {$unwind: "$products"},
    {$match: match},
    {$project: project},
    {$group: {
        _id: "$line",
        total: { $sum: "$total" }
    }}

], function(err, docs){
    console.log(docs);
});

$unwind 属性,否则它会尝试将$total 返回的数组相加。

【讨论】:

  • project["line"] 语句似乎不起作用(文档返回undefined)但没有它,totalpriceExists 似乎起作用了。做一些测试...
  • 这是返回按日期匹配的记录总数,而不是实际 totalprice 字段的总和。
  • 我更新了你的答案。这有效,除了按年/月/日字段分组。这不是 OP 的一部分,但是我实际上想让这部分工作,它非常有用。
猜你喜欢
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 2016-11-16
  • 2021-03-30
  • 2015-10-04
  • 2019-02-11
  • 2017-12-10
  • 2019-04-28
相关资源
最近更新 更多