You need to change the structure of your documents by updating them. You will need to loop through each document using the .forEach method, then $unset all the field name starting with product_ . From there, you will need to add new products fields, which are an array of products using the $set update operator. In doing so, you should use "bulk" to update your documents for maximum efficiency.
var bulkOp = db.collection.initializeOrderedBulkOp(); var count = 0; db.collection.find().forEach(function(doc) { var allproducts = []; for(var key in doc) { if(Object.prototype.hasOwnProperty.call(doc, key) && /^product_\d+/.test(key)) { var product = {}; product["name"] = key; product["orderCancelled"] = doc[key]["orderCancelled"]; product["orderDelivered"] = doc[key]["orderDelivered"]; allproducts.push(product); var unsetField = {}; unsetField[key] = ""; bulkOp.find({"_id": doc._id}).update({ "$unset": unsetField }); }; count++; }; bulkOp.find({"_id": doc._id}).update({ "$set": { "products": allproducts } }); count++; if(count % 500 === 0) {
Your documents will look like this:
{ "_id" : NumberLong(542), "products" : [ { "name" : "product_1", "orderCancelled" : 0, "orderDelivered" : 6 }, { "name" : "product_2", "orderCancelled" : 3, "orderDelivered" : 16 }, { "name" : "product_3", "orderCancelled" : 5, "orderDelivered" : 11 } ] }
Then, your aggregation request is executed using the .aggregate() method:
db.collection.aggregate([ { "$match": { "_id": 542 } }, { "$unwind": "$products" }, { "$group": { "_id": "$_id", "maxOrderCancelled": { "$max": "$products.orderCancelled"}, "minOrderDelivvered": { "$min": "$products.orderDelivered"} }} ])
What returns:
{ "_id" : NumberLong(542), "maxOrderCancelled" : 5, "minOrderDelivvered" : 6 }
From version 3.2 you can use $max and $min in $project , which is a much better way to do this because there is no need for $unwind your array first.
db.collection.aggregate([ { "$match": { "_id": 542 } }, { "$project": { "maxOrderCancelled": { "$max": { "$map": { "input": "$products", "as": "order", "in": "$$orc.orderCancelled" } } }, "minOrderDelivered": { "$min": { "$map": { "input": "$products", "as": "orc", "in": "$$orc.orderDelivered" } } } }} ])
What gives:
{ "_id" : NumberLong(542), "maxOrderCancelled" : 5, "minOrderDelivered" : 6 }