Search code examples
javascriptnode.jslogiclodashbackend

How to group objects according to a property


Hope someone can help me,

The situation: I'm developing a unit report where I select all my clients with their unit_id (the unit_id is a relationship with unit, where they can be located) and this select is an array of array of objects, and I'm having a trouble with how to group objects according to one specific property, I have an array like:

const clients = [
  [
    {
      ID: 1,
      NAME: 'John Doe',
      UNITS: ['02'],
    }
  ],
  [
    {
      ID: 2,
      NAME: 'Jane Doe',
      UNITS: ['01', '02'],
    }
  ],
  [
    {
      ID: 3,
      NAME: 'Doe John',
      UNITS: ['50', '15'],
    }
  ],
  [
    {
      ID: 4,
      NAME: 'Doe Jane',
      UNITS: ['30'],
    }
  ],
  [
    {
      ID: 5,
      NAME: 'Doe Jane',
      UNITS: ['15'],
    }
  ],
]

The problem: I need to group each individual with the same 'UNIT', but I can't have multiple groups with the same 'UNIT ID' that I have in one group, I'm expecting a result like:

const unitGroups = [
  [
    {
      UNIT_IDS: ['01', '02'],
      CLIENTS: [
        {
          ID: 1,
          NAME: 'John Doe',
        }, 
        {
          ID: 2,
          NAME: 'Jane Doe',
        }
      ]
    }
  ],
  [
    {
      UNIT_IDS: ['50', '15'],
      CLIENTS: [
        {
          ID: 3,
          NAME: 'Doe John',
        },
        {
          ID: 5,
          NAME: 'Doe Jane',
        }
      ]
    }
  ],
  [
    {
      UNIT_IDS: ['30'],
      CLIENTS: [
        {
          ID: 4,
          NAME: 'Doe Jane',
        }
      ]
    }
  ]
]

Solution

  • You can make use of reduce in order to achieve the result. Here is an implementation:

    const clients = [ [ { ID: 1, NAME: 'John Doe', UNITS: ['02'], } ], [ { ID: 2, NAME: 'Jane Doe', UNITS: ['01', '02'], } ], [ { ID: 3, NAME: 'Doe John', UNITS: ['50', '15'], } ], [ { ID: 4, NAME: 'Doe Jane', UNITS: ['30'], } ], [ { ID: 5, NAME: 'Doe Jane', UNITS: ['15'], } ]];
    
    const result = clients.reduce((a,e)=>{
       e.forEach(({UNITS, ...rest})=>{
        const getIndex = a.findIndex(p=>p.UNIT_IDS.some(b=>UNITS.some(c=>c===b)));
        if(getIndex===-1){
           const newData = {UNIT_IDS:UNITS, CLIENTS:[].concat(rest)};
           a.push(newData);
           } else {
           a[getIndex].UNIT_IDS = [...new Set([...a[getIndex].UNIT_IDS, ...UNITS])];
           a[getIndex].CLIENTS = [...a[getIndex].CLIENTS, rest]
           }
        })
      return a;
    },[]);
    
    console.log(result);