在 meteor 中使用 MongoDB 聚合时无法获得正确的结果

Cannot get correct result when using MongoDB aggregation in meteor

本文关键字:结果 meteor MongoDB      更新时间:2023-09-26

我在meteor中使用MongoDB聚合。

数据库中的项目如下所示:

项目1

{
  products: {
    aaa: 100,
    bbb: 200
  }
}

项目2

{
  products: {
    aaa: 300,
    bbb: 400
  }
}

我的管道如下所示

 let pipeline = [{
    $limit: 10
  }, {
    $group: {
      _id: {
        // …
      },
      total: {
        $sum: "$products.aaa"
      }
    }
  }];

而且它工作得很好。但是当我将数据库结构更改为此时

项目1

{
  products: [
    {code: "aaa", num: 100},
    {code: "bbb", num: 200}
  ]
}

项目2

{
  products: [
    {code: "aaa", num: 300},
    {code: "bbb", num: 400}
  ]
}

我得到的结果总是 total,我认为我的管道是错误的。请看里面的评论:

 let pipeline = [{
    $limit: 10
  }, {
    $group: {
      _id: {
        // …
      },
      total: {
        $sum: "$products.0.num"  // Neither this nor "$products[0].num" works
      }
    }
  }];

那么我怎样才能正确地写出来呢?谢谢

使用 MongoDB 3.2(它不会是与 meteor 捆绑的服务器,但需要注意停止您使用单独的服务器实例。实际上会推荐)您可以将$arrayElemAt$map一起使用:

let pipeline = [
    { "$limit": 10 }, 
    { "$group": {
      "_id": {
        // …
      },
      "total": {
        "$sum": { "$arrayElemAt": [
            { "$map": {
                "input": "$products",
                "as": "product",
                "in": "$$product.num"
            }},
            0
        ]}
      }
    }}
];

对于旧版本,使用"两个"$group阶段和$first运算符处理后使用 $unwind .这只是"第一个"指数值:

let pipeline = [
    { "$limit": 10 },
    { "$unwind": "$products" },
    { "$group": {
        "_id": "$_id",       // The document _id
        "otherField": { "$first": "$eachOtherFieldForGroupingId" },
        "productNum": { "$first": "$products.num" }
    }},
    { "$group": {
      "_id": {
        // …
      },
      "total": {
        "$sum": "$productNum"
      }
    }}
];

因此,在后一种情况下,在您$unwind之后,您只想使用 $first 从数组中获取"第一个"索引,并且它还将用于从原始文档中获取要用作分组键一部分的每个字段。$unwind 之后,将为每个数组成员复制所有元素。

在前一种情况下,$map 只提取每个数组成员的"num"值,然后$arrayElemAt只检索所需的索引位置。

当然,MongoDB 3.2的新方法更好。如果你想要另一个数组索引,那么你需要从数组中重复获取$first元素,并不断从数组结果中过滤掉它,直到达到所需的索引。

因此,虽然在早期版本中是可能的,但要实现这一点需要做很多工作。