Mongo查询没有给出聚合函数的确切结果

我的mongo数据库包含一个“商店”集合,数据如下所示:

{ "_id" : ObjectId("XXXX1b83d2b227XXXX"), "ShopId" : 435, "products" : [ { "productId" : "1234", "productName" : "non veg", "productCategory" : "meals", "mrp" : "38", }, { "productId" : "5234", "productName" : "non veg", "productCategory" : "meals", "mrp" : "38", }, { "productId" : "6234", "productName" : "apple", "productCategory" : "juice", "mrp" : "38", }, { "productId" : "7234", "productName" : "non veg", "productCategory" : "biriyani", "mrp" : "38", }, { "productId" : "8234", "productName" : "non veg", "productCategory" : "biriyani", "mrp" : "38", } ] } 

集合中将有几个商店有一个产品清单。

预期产出

  { "productList": [ { "categoryname": "meals", "productcount": "2", "products": [ { "productname": "Non-Veg" }, { "productname": "Veg" } ] }, { "categoryname": "juice", "productcount": "1", "products": [ { "productname": "apple" } ] },{......} ] } 

我用2个查询使用“asynchronous”方法,但我没有得到正确的输出。 我认为可以在不使用“asynchronous”的情况下在一个查询中完成。

我的代码如下,我认为这是错误的方法:

 model.Shops.aggregate([ {$match:{ShopId:435}}, {$unwind:"$products"}, {$limit:2},{$skip:0}, {$group:{_id:{"productCategory":"$products.productCategory"}}} ],function (err, doc) { if (doc!=null){ var arr = []; async.each(doc, function(item,callback){ model.Shops.aggregate([ {"$unwind":"$products"}, {$match:{"ShopId":435,"products.productCategory":item._id.productCategory}}, {$limit:2}, { $group: { _id:null, "products": { $push:{"productName":"$products.productName"} } } } ], function (err,doc) { arr.push({"categoryname":item._id.productCategory,"products":doc.products}); callback(null); }); },function (err) { res.json(arr); }); } }); 

你当然不需要两个查询,一个pipe道就足够了。 运行以下集合操作以获得所需的结果:

 model.Shops.aggregate([ { "$match": { "ShopId": 435 } }, { "$unwind": "$products" }, { "$group": { "_id": "$products.productCategory", "count": { "$sum": 1 }, "products": { "$push": { "productName": "$products.productName" } } } }, { "$group": { "_id": null, "productList": { "$push": { "categoryname": "$_id", "productcount": "$count", "products": "$products" } } } } ], function (err, results) { res.json(results); }); 

说明

上面的stream水线使用以下stream水线步骤(按给定的顺序)并解释为:

步骤1) $match运算符用于过滤进入stream水线的文档。 如果您来自SQL后台,则此pipe道与SQL的WHERE子句类似,例如

 SELECT * FROM Shops WHERE ShopId = 435 

如果仅在此阶段运行stream水线,则将返回与435的ShopId相匹配的所有文档

步骤2) $unwindproducts领域是一个数组,所以你需要添加一个$unwind阶段到你的pipe道,以便你可以压扁数组,因为它需要作为一个非规范化的领域进一步处理。 对于每个input文档,这将输出n文档,其中n是数组元素的数量,对于空数组可以为零。

对于上面的例子运行到这个阶段的总pipe道将产生5个文件,即在mongo shell中

 db.getCollection('shops').aggregate([ { "$match": { "ShopId": 435 } }, // Step 1 { "$unwind": "$products" } // Step 2 ]) 

会屈服

 [ { "_id" : ObjectId("58aadec0671a3794272f342f"), "ShopId" : 435, "products" : { "productId" : "1234", "productName" : "non veg", "productCategory" : "meals", "mrp" : "38" } }, { "_id" : ObjectId("58aadec0671a3794272f342f"), "ShopId" : 435, "products" : { "productId" : "5234", "productName" : "non veg", "productCategory" : "meals", "mrp" : "38" } }, { "_id" : ObjectId("58aadec0671a3794272f342f"), "ShopId" : 435, "products" : { "productId" : "6234", "productName" : "apple", "productCategory" : "juice", "mrp" : "38" } }, { "_id" : ObjectId("58aadec0671a3794272f342f"), "ShopId" : 435, "products" : { "productId" : "7234", "productName" : "non veg", "productCategory" : "biriyani", "mrp" : "38" } }, { "_id" : ObjectId("58aadec0671a3794272f342f"), "ShopId" : 435, "products" : { "productId" : "8234", "productName" : "non veg", "productCategory" : "biriyani", "mrp" : "38" } } ] 

步骤3) $group pipeline步骤,通过非规范化文档中的productCategory字段对pipe道中的文档进行分组,并创build一个数组products ,该products具有来自上一个pipe道的字段。 $grouppipe道运算符类似于SQL的GROUP BY子句。

在SQL中,除非使用任何聚合函数,否则不能使用GROUP BY 。 同样的,你也必须在MongoDB中使用一个名为accumulator的聚合函数。 你可以在这里阅读更多关于聚合函数。

您需要创build数组的累加器操作符是$push

在同一个$group操作中,计算总计数的逻辑即每个类别组中的文档数量是使用$sum累加器操作符完成的。 expression式{ $sum : 1 }返回每个组中文档数量的总和。

要了解pipe道,请在此阶段运行操作并分析结果。 所以,执行等效的mongo操作

 db.getCollection('shops').aggregate([ { "$match": { "ShopId": 435 } }, // Step 1 { "$unwind": "$products" }, // Step 2 { // Step 3 "$group": { "_id": "$products.productCategory", "count": { "$sum": 1 }, "products": { "$push": { "productName": "$products.productName" } } } } ]) 

产生以下文件

 [ { "_id" : "meals", "count" : 2, "products" : [ { "productName" : "non veg" }, { "productName" : "non veg" } ] }, { "_id" : "juice", "count" : 1, "products" : [ { "productName" : "apple" } ] }, { "_id" : "biriyani", "count" : 2, "products" : [ { "productName" : "non veg" }, { "productName" : "non veg" } ] } ] 

第四步)当你指定一个_id的值为null来计算上面所有input文档的累积值时,最后的$grouppipe道会产生所需的结果。 所需的结构有一个可以使用$push操作符创build的productsList数组。

再次,在这个阶段运行最后的聚合pipe道将会给你想要的结果,即在mongo shell中执行这个

 db.getCollection('shops').aggregate([ { "$match": { "ShopId": 435 } }, // Step 1 { "$unwind": "$products" }, // Step 2 { // Step 3 "$group": { "_id": "$products.productCategory", "count": { "$sum": 1 }, "products": { "$push": { "productName": "$products.productName" } } } }, { // Step 4 "$group": { "_id": null, "productList": { "$push": { "categoryname": "$_id", "productcount": "$count", "products": "$products" } } } } ]) 

会屈服

 { "_id" : null, "productList" : [ { "categoryname" : "meals", "productcount" : 2, "products" : [ { "productName" : "non veg" }, { "productName" : "non veg" } ] }, { "categoryname" : "juice", "productcount" : 1, "products" : [ { "productName" : "apple" } ] }, { "categoryname" : "biriyani", "productcount" : 2, "products" : [ { "productName" : "non veg" }, { "productName" : "non veg" } ] } ] } 

在这里需要注意的一点是,在执行一个pipe道时,MongoDB将pipe道运算符互相连接起来。 这里的“pipe道”是指Linux的含义:操作员的输出成为下一个操作员的input。 每个操作员的结果是一个新的文件集合。 所以Mongo执行上面的stream水线如下:

 collection | $match | $unwind | $group | $group => result