简体   繁体   English

遍历MongoDB聚集查询产生的数组

[英]Iterating through array produced by MongoDB aggregation query

Good afternoon all, 大家下午好

I am having a really tough time working with aggregation queries in MongoDB 3.4. 我在MongoDB 3.4中处理聚合查询时非常艰难。 I have a problem that is asking me to do push the results of my aggregation query into an empty array called categories which I have been able to do successfully using this code: 我有一个问题,要求我将聚合查询的结果推送到一个名为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 looks like this: 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 } ]

Next I have the following task: 接下来,我有以下任务:

  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. 

The problem is that it seems like inside my .toArray() method the data parameter sometimes acts like an array and sometimes not. 问题在于,似乎在我的.toArray()方法内部, data参数有时像数组,有时却像数组。 For example if I wanted to add perhaps just the value of the num key to the categories array like so: categories.push(...data["num"]) I get an error stating undefined is not iterable . 例如,如果我想将num键的值仅添加到categories数组中,例如: categories.push(...data["num"])我收到一条错误消息,指出undefined is not iterable

Since I cannot iterate over each data.num key I cannot extract it's value and add it to a running total of all data.num values. 由于无法遍历每个data.num键,因此无法提取其值并将其添加到所有data.num值的运行总计中。

What am I not understanding about what is going on here? 我对这里发生的事情不了解什么?

You don't need to use application logic to group data, mongoDB aggregation is made for this task. 您无需使用应用程序逻辑来对数据进行分组,此任务进行了mongoDB聚合。 Add another $group to your query with a new field All that $sum your $num field and $push all documents to a new field called categories : 使用新字段将另一个$group添加到您的查询中, All $sum将您的$num字段和$push所有文档$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"
            }
        }
    }
}])

It gives : 它给 :

{
    "_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
    }]
}

For consuming the output, data is an array , to access the first element use data[0] : 为了使用输出, 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);
    }
})

What I wanted to achieve was pushing or unshifting as we'll see in a moment an object that looked like this into my categories array: 我想要实现的是推动或保持不变,我们稍后将看到一个类似以下内容的对象进入我的categories数组:

var allCategory = {
      _id: "All",
      num: [sum of all data.num values]
}

I ended up messing with .reduce() method and used it on the categories array. 我最终.reduce()方法弄乱了,并在categories数组上使用了它。 I got lucky through some console.log -ing and ended up making this: 我很幸运通过一些console.log -ing并最终做到了:

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);
        })

First I use a spread operator to push all the objects from data into categories . 首先,我使用散布运算符将data所有对象推入categories Then declare sum which runs .reduce() on categories returning the accumulation of val["num"] which is really data.num (console log is life). 然后声明对categories运行.reduce() sum ,返回真正是data.numval["num"] data.num (控制台日志就是生命)。 I create the allCategory document/object then use .unshift to place it at the beginning of my categories array (this placement was a requirement) then use my callback. 我创建了allCategory文档/对象,然后使用.unshift将其放在我的categories数组的开头(此位置是.unshift ),然后使用回调。

I think it's a hacky way of accomplishing my goal and I had to go through some trial and error as to the correct order of methods and variables in my .toArray() . 我认为这是实现目标的一种简单方法,我必须对.toArray()中方法和变量的正确顺序进行一些试验和错误。 Yet it worked and I learned something. 然而它奏效了,我学到了一些东西。 Thanks for the help @Bertrand Martel . 感谢@Bertrand Martel的帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM