迭代MongoDB聚合查询产生的数组

大家下午好,

我在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值的运行总计。

我不了解这里发生了什么?

您不需要使用应用程序逻辑对数据进行分组,mongoDB聚合就是为这个任务做的。 添加另一个$group到您的查询与一个新的领域All $sum您的$num字段和$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); } }) 

我想实现的是推动或不移动,因为我们马上就会看到一个像这样的对象我的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 。 然后声明在返回val["num"]的累积的categories上运行.reduce()真正的data.num (控制台日志是life)。 我创build了allCategory文档/对象,然后使用.unshift把它放在我的categories数组的开始处(这个位置是一个需求),然后使用我的callback.unshift

我认为这是一个很好的方法来完成我的目标,我必须通过一些试验和错误的方法和variables在我的.toArray()正确的顺序。 然而,它工作,我学到了一些东西。 感谢@Bertrand Martel的帮助。