一个请求中的多个聚合函数

时间:2015-03-18 14:20:45

标签: node.js mongodb mongoose mongodb-query aggregation-framework

我有一个数据集如下:

{
  item: '123',
    array: [{
      array2:[{
        array3: [{
          property1: 1234
        }]
      }],
      anotherArray: [{
        property2: 1234
      }]
    }]
}

我试图在同一个请求中汇总property2和property one的总和。 这是我目前的聚合函数:

Item.aggregate([
            {$match: {itemId: 1234}},
            {$unwind: "$array"},
            {$unwind: "$array.array2"},
            {$unwind: "$array.array2.array3"},
            {$unwind: "$array.anotherArray"},
            {$group: {
                _id: 0,
                property1: {$sum: '$array.array2.array3.property1'},
                property2: {$sum: '$array.anotherArray.property2'}

            }},
            {$project: {
                _id: 0,
                property1: "$property1",
                property2: "$property2",

            }},
        ], function (err, aggregate) {
            callback(null, aggregate);
        });

问题是属性1和2的聚合结果总是它们应该是的两倍。

我猜问题是“sunArray”的$ unwind,因为当我删除它时,我得到了正确的聚合值。

是否可以使用一个聚合函数在多个数组上进行聚合?

目前我只是使用异步并行向db发出2个不同的请求,但是我想在未来进行更复杂的聚合而不需要额外的db调用。

2 个答案:

答案 0 :(得分:2)

如上所述,结构不是很好,应该根据其意图进行审查。它真的不清楚为什么它如此结构化,或者在任何一种情况下阵列中的任何其他内容都会弄乱结果。

但是当文档中有多个数组时,有一种通用的方法,基本上是分别处理每个数组并获得#34;总数"首先是每个文件。然后总结所有文件中的总数:

Item.aggregate([
    // Unwind only 1 inner array first
    { "$unwind": "$array" },
    { "$unwind": "$array.array2" },
    { "$unwind": "$array.array2.array3" },

    // Group back the sum of the element and the first of the other array
    // and only per document
    { "$group": {
        "_id": "$_id",
        "property1": { "$sum": "$array.array2.array3.property1" },
        "anotherArray": { "$first": "$array.anotherArray" }
    }},

    // Unwind the other array
    { "$unwind": "$anotherArray" },

    // Group back the total and the first summed per document
    { "$group": {
        "_id": "$_id",
        "property1": { "$first": "$property1" },
        "property2": { "$sum": "$anotherArray.property2" }
    }},

    // Total all documents and output
    { "$group": {
        "_id": null,
        "property1": { "$sum": "$property1" },
        "property2": { "$sum": "$property2" },
    }},
    { "$project": {
        "_id": 0,
        "property1": 1,
        "property2": 1
    }}
],callback);

因此,通过一次仅包含一个数组并且仅在原始文档中获取总计,可以避免为另一个数组的每个展开项创建多个副本的重复问题。使用离散文档总计,可以很容易地从所需的选择中获得总计。

答案 1 :(得分:0)

最后,我找到了一个使用MongoDB $ setUnion的用例的解决方案。

以下是我用于问题的代码:

Item.aggregate([
            {$match: { itemID: '1234'}},
            {$unwind: "$array1"},
            {$unwind: "$array1.array2"},
            {$project: {
                _id: 0,
                combined: {$setUnion: ['$array1.anotherArray', '$array1.array2.array3']},

            }},
            {$unwind: "$combined"},
            {$group: {
                _id: 0,
                property1: {$sum: '$combined.property1'},
                property2: {$sum: '$combined.property2'}
            }},
        ], function (err, aggregate) {
            cb(aggregate);
        });