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) $unwind
– products
领域是一个数组,所以你需要添加一个$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道的字段。 $group
pipe道运算符类似于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文档的累积值时,最后的$group
pipe道会产生所需的结果。 所需的结构有一个可以使用$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