如何对MongoDB集合中字段的不同值求和(使用mongoose)

时间:2014-11-30 12:34:58

标签: node.js mongodb mongoose aggregation-framework

想象一下,我有一个名为 journals 的集合,其中包含以下文档:

{
  "article": "id1",
  "d": 2
},
{
  "article": "id1",
  "d": 2
},
{
  "article": "id1",
  "d": 3
},
{
  "article": "id2",
  "d": 2
},
...

其中 d 是一种开关,文章是一个参考。现在我希望得到如下结果:

[
  {
    "_id": "id1",
    "total": 3,
    "d2": 2,
    "d3": 1
  },
  {
    "_id": "id2",
    "total": 1,
    "d2": 1,
    "d3": 0
  }
]

我使用 mongoose 并拥有一个名为 Journal 的模型。到目前为止我得到的是......

Journal.aggregate(
  { $project: {
    articleId: 1,
    depth2 : { $gte:['$d', 2] },
    depth3 : { $eq:['$d', 3] }
  }},
  { $group: {
      _id: '$article',
      total: { $sum: 1 },
      d2: { $sum: '$depth2'},
      d3: { $sum: '$depth3'}
    }
  },
  function (err, journal) {
    console.log(journal);
  }
);

导致:

[
  {
    "_id": "id1",
    "total": 3,
    "d2": 0,
    "d3": 0
  },
  {
    "_id": "id2",
    "total": 1,
    "d2": 0,
    "d3": 0
  }
]

显然,这里的错误是$eq:['$d', 3]未被总结,因为这会导致布尔值。

那么是否有更好的表达式将新的depth2和depth3字段投影到10而不是truefalse
或者是否有完整而更好的方法? :)

我希望避免进行3次查询,并在{ $match: { d: 2 } }之前添加匹配阶段。

1 个答案:

答案 0 :(得分:2)

您可以使用$cond将布尔值转换为数字值,但您还有一个$gte $eq应该是article并且您的文档使用{ {1}}代码使用articleId

Journal.aggregate([
  { $project: {
    article: 1,
    depth2 : { $cond: [{$eq: ['$d', 2]}, 1, 0] },
    depth3 : { $cond: [{$eq: ['$d', 3]}, 1, 0] }
  }},
  { $group: {
      _id: '$article',
      total: { $sum: 1 },
      d2: { $sum: '$depth2'},
      d3: { $sum: '$depth3'}
    }
  }
]);

输出:

{
    "result" : [ 
        {
            "_id" : "id2",
            "total" : 1,
            "d2" : 1,
            "d3" : 0
        }, 
        {
            "_id" : "id1",
            "total" : 3,
            "d2" : 2,
            "d3" : 1
        }
    ],
    "ok" : 1
}