Search code examples
javascriptmetaprogrammingreduce

Grouping Objects by subdocument value - Adapting the Array.reduce method (metaprogramming?)


I found a clear answer on how to group using reduce.

Most efficient method to groupby on an array of objects

const array = [ 
  { _id:" 5fbcca92c36b24d99395623d",
    assetData:
     { _id: "5fbcca159ae5f2d8ed792542",
       name: 'House 1',
       numberOfRooms: '1',
       numberOfBathrooms: '2' } },
  { _id: "5fbcca92c36b24d99395623c",
    assetData:
     { _id: "5fbcca159ae5f2d8ed792542",
       name: 'House 1',
       numberOfRooms: '1',
       numberOfBathrooms: '2' } },
  { _id: "5fbccb32c36b24d993956242",
    assetData:
     { _id: "5fbbedcb4decb58513e4ba80",
       name: 'House 2',
       numberOfRooms: '1',
       numberOfBathrooms: '1' } },
  { _id: "5fbccb32c36b24d993956243",
    assetData:
     { _id: "5fbbedcb4decb58513e4ba80",
       name: 'House 2',
       numberOfRooms: '1',
       numberOfBathrooms: '1' } },
 ];
 
const groupBy = function (xs, key) {
  return xs.reduce(function (rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};
 
 const test = Object.entries(groupBy(array, "_id"));
 
 console.log(test);

I'm trying to adapt to, instead of sorting by the _id, sort by assetData._id. Changing the key argument on the groupBy function, do not the output's behavior. It does not accept the value of a subdocument. I don't know even how to proceed with my research because I couldn't really understand what this part of the function (rv[x[key]] = rv[x[key]] || []) means. I started reading something about metaprogramming in ES6, but I'm not sure if it will lead me to an answer. Any tip?


Solution

  • Well, since I have no theoretical response yet, I tried to solve the problem in a practical way. It seems that I can't pass the string assetData._id straight into the key argument. Maybe someone later will pop up with the reason. For now, to obtain the result I expected, I split the key into key and subkey and passed assetData separated from _id. The final code is:

    const array = [ 
      { _id:" 5fbcca92c36b24d99395623d",
        assetData:
         { _id: "5fbcca159ae5f2d8ed792542",
           name: 'House 1',
           numberOfRooms: '1',
           numberOfBathrooms: '2' } },
      { _id: "5fbcca92c36b24d99395623c",
        assetData:
         { _id: "5fbcca159ae5f2d8ed792542",
           name: 'House 1',
           numberOfRooms: '1',
           numberOfBathrooms: '2' } },
      { _id: "5fbccb32c36b24d993956242",
        assetData:
         { _id: "5fbbedcb4decb58513e4ba80",
           name: 'House 2',
           numberOfRooms: '1',
           numberOfBathrooms: '1' } },
      { _id: "5fbccb32c36b24d993956243",
        assetData:
         { _id: "5fbbedcb4decb58513e4ba80",
           name: 'House 2',
           numberOfRooms: '1',
           numberOfBathrooms: '1' } },
     ];
     
    const groupBy = function (xs, key, subkey) {
      return xs.reduce(function (rv, x) {
        (rv[x[key][subkey]] = rv[x[key][subkey]] || []).push(x);
        return rv;
      }, {});
    };
    
    const test = Object.entries(groupBy(array, "assetData", "_id"))
    
    console.log(test)

    I'm open to more enlightened answers!