由MongoDB聚合查询生成的数组迭代

4

大家下午好,

我在处理MongoDB 3.4中的聚合查询时遇到了一些困难。我的问题要求我将聚合查询的结果推送到一个名为categories的空数组中,我成功地使用以下代码完成了这个任务:

var categories = [];

    database.collection("item").aggregate([{
        $group : {
            _id : "$category",
             num : {$sum : 1}
         }},
        {$sort:{_id:1}}]).toArray(function(err, data){

            categories.push(...data);
            callback(categories);
            console.log(categories);
        })

    }

categories看起来像这样:

[ { _id: 'Apparel', num: 6 },
{ _id: 'Books', num: 3 },
{ _id: 'Electronics', num: 3 },
{ _id: 'Kitchen', num: 3 },
{ _id: 'Office', num: 2 },
{ _id: 'Stickers', num: 2 },
{ _id: 'Swag', num: 2 },
{ _id: 'Umbrellas', num: 2 } ]

接下来我有以下任务:

     In addition to the categories created by your aggregation query,
     include a document for category "All" in the array of categories
     passed to the callback. The "All" category should contain the total
     number of items across all categories as its value for "num". The
     most efficient way to calculate this value is to iterate through
     the array of categories produced by your aggregation query, summing        
     counts of items in each category.
问题在于似乎在我的.toArray()方法内,data参数有时表现得像数组,有时不是。例如,如果我想仅将num键的值添加到categories数组中,如下所示:categories.push(...data["num"]),则会出现错误,指出undefined is not iterable
由于我无法迭代每个data.num键,因此无法提取其值并将其添加到所有data.num值的运行总和中。
我对这里发生的事情有什么误解吗?
2个回答

5
您无需使用应用程序逻辑来分组数据,MongoDB聚合功能是为此任务而设计的。将另一个 $group 添加到您的查询中,并使用一个新字段 All 将您的 $num 字段 $sum,并使用 $push 将所有文档推送到名为 categories 的新字段中:
db.item.aggregate([{
    $group: {
        _id: "$category",
        num: { $sum: 1 }
    }
}, { $sort: { _id: 1 } }, {
    $group: {
        _id: 1,
        All: { $sum: "$num" },
        categories: {
            $push: {
                _id: "$_id",
                num: "$num"
            }
        }
    }
}])

它提供了:

{
    "_id": 1,
    "All": 23,
    "categories": [{
        "_id": "Swag",
        "num": 2
    }, {
        "_id": "Office",
        "num": 2
    }, {
        "_id": "Stickers",
        "num": 2
    }, {
        "_id": "Apparel",
        "num": 6
    }, {
        "_id": "Umbrellas",
        "num": 2
    }, {
        "_id": "Kitchen",
        "num": 3
    }, {
        "_id": "Books",
        "num": 3
    }, {
        "_id": "Electronics",
        "num": 3
    }]
}

要消费输出,data 是一个 数组,要访问第一个元素,请使用 data[0]

var categories = [];

database.collection("item").aggregate([{
    $group: {
        _id: "$category",
        num: { $sum: 1 }
    }
}, { $sort: { _id: 1 } }, {
    $group: {
        _id: 1,
        All: { $sum: "$num" },
        categories: {
            $push: {
                _id: "$_id",
                num: "$num"
            }
        }
    }
}]).toArray(function(err, data) {

    var totalCount = data[0]["All"];
    console.log("total count is " + totalCount);

    categories = data[0]["categories"];

    for (var i = 0; i < categories.length; i++) {
        console.log("category : " + categories[i]._id + " | count : " + categories[i].num);
    }
})

你的解决方案接近我所寻找的,我很感谢你的回复。在你的帮助下,我认为我对正在处理的问题有了更好的理解。唯一不清楚的是需要将新的 {category: "All} 文档作为 data 数组的一部分。我会在你的答案下面发布我的答案,这样你就可以看到我的意图。 - m00saca

-1
我想要实现的是将一个看起来像这样的对象“推入”或“插入”到我的“categories”数组中。
var allCategory = {
      _id: "All",
      num: [sum of all data.num values]
}

我最终折腾了一下.reduce()方法,并在categories数组中使用它。通过一些console.log测试,我幸运地做出了这个:

var categories = [];

    database.collection("item").aggregate([{
        $group : {
            _id : "$category",
             num : {$sum : 1}
         }},
        {$sort:{_id:1}}]).toArray(function(err, data){
            categories.push(...data);
            var sum = categories.reduce(function(acc, val){
                // console.log(acc, val["num"])
                return acc + val["num"]
            },0);

            var allCategory = {
                _id: "All",
                num: sum
            }
            categories.unshift(allCategory)
            callback(categories);
        })

首先,我使用扩展运算符将data中的所有对象推入categories。然后声明sum,它在categories上运行.reduce(),返回val["num"]的累加值,这实际上是data.num(控制台日志很重要)。我创建了allCategory文档/对象,然后使用.unshift将其放置在我的categories数组的开头(这个位置是必需的),然后使用我的回调函数。

我认为这是一种hacky的方法来完成我的目标,我不得不经历一些试错,以确定在.toArray()中正确的方法和变量顺序。但它起作用了,我学到了东西。感谢@Bertrand Martel的帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接