How to convert array of objects into nested object in MongoDB aggregation pipeline

I am currently doing a project where my Database Management System is MongoDB. I am writing an aggregation pipeline where there are several stages. I am currently struggling at a particular stage where I want to obtain the following output. MongoDB has so many operator expressions that I am confused about which one to use to achieve this. I have a collection called Styles and Skus which are as follows:

// Schema for styles
const styles = mongoose.Schema({
  id: Number,
  productId: Number,
  name: String,
  sale_price: String,
  original_price: String,
  default_price: Boolean,
}, {
  strict: false,
});

// Schema for skus
const skus = mongoose.Schema({
  id: Number,
  styleId: Number,
  size: String,
  quantity: String,
}, {
  strict: false,
});

Each style can have several SKUs, one-to-many relationships. In my aggregation pipeline, I am using $lookup to find all the SKUs of that particular style and adding a new field called SKUs in the styles document. I am getting results like this after the $lookup.

{
           "style_id": 1,
           "name": "Forest Green & Black",
           "original_price": "140",
           "sale_price": "0",
           "default?": true,
            "skus": [
               { 
                  "id": 37,
                  "styleId": 1,
                  "size": "XS",
                  "quantity": 16 
               },
               { 
                  "id": 38,
                  "styleId": 1,
                  "size": "S",
                  "quantity": 8
               } 
             ]  

}

Which is expected as $lookup returns a matching array. But I want my Styles document to look like this.

{
            "style_id": 1,
            "name": "Forest Green & Black",
            "original_price": "140",
            "sale_price": "0",
            "default?": true,
             "skus": {
                  "37": {
                    "styleId": 1,
                   "size": "XS",
                   "quantity": 16 
                  },
                  "38": {
                   "styleId": 1,
                   "size": "S",
                   "quantity": 8
                  }
               }
                    

}

Can someone give any idea how to structure the data like above in aggregation pipeline? Any help would be greatly appreciated. Thanks in advance.

You are in luck. See https://docs.mongodb.com/manual/reference/operator/aggregation/arrayToObject/ you might need to do some $project or $map first.

Be aware that some client drivers do not like numbers as field keys and might build a sparse array anyway. See Mongodb import object with numbers as keys results in array

Personally, I would keep it as an array as I find it is cleaner and more representative of what the data is. You could pass skus[n] to a function and you would have everything about the sku. Otherwise you wound need to pass the key (ie: 37) and the object to have all the info about the sku because sku.37 does not have the key. It would make further $match harder to do because 37 is really data not a key.

image
getting this error($arrayToObject requires an object keys of ‘k’ and ‘v’. Found incorrect number of keys:5)
image

please help me

1 Like

If you look at the documentation you will see that your array product does not fulfill the initial requirements.

You will need to first use $map to modify your array to match the requirement.

More importantly, why do you want to apply this transformation?