Search code examples
javascriptnuxt.jsvuejs3lodash

Group Array by Object key where key is an object


I want to group this array by rg_ext objectKey, where every key inside of rg_ext is equal matches with rg_ext in other object.

like this..

const RoomsPrices = ref([
  {
    rg_ext: {
      class: 5,
      quality: 0,
      sex: 0,
      bathroom: 2,
      bedding: 3,
      family: 0,
      capacity: 2,
      club: 0,
    },
    room_name: "2 Bedrooms Double Suite (full double bed)",
    cost: 10000,
    priceid: 15464,
  },
  {
    rg_ext: {
      class: 3,
      quality: 0,
      sex: 0,
      bathroom: 2,
      bedding: 2,
      family: 0,
      capacity: 3,
      club: 0,
    },
    room_name: "3 Bedrooms Double Suite (full double bed)",
    cost: 14000,
    priceid: 12464,
  },
  {
    rg_ext: {
      class: 3,
      quality: 0,
      sex: 0,
      bathroom: 2,
      bedding: 2,
      family: 0,
      capacity: 3,
      club: 0,
    },
    room_name: "3 Bedrooms Double Suite (full double bed)",
    cost: 14000,
    priceid: 12464,
  },
  {
    rg_ext: {
      class: 5,
      quality: 0,
      sex: 0,
      bathroom: 2,
      bedding: 3,
      family: 0,
      capacity: 2,
      club: 0,
    },
    room_name: "2 Bedrooms Double Suite (full double bed)",
    cost: 16300,
    priceid: 36464,
  },
]);

I am trying to achieve this using Lodash in NuxtJs.

const RoomGroup = computed(() => {
  const GP = useGroupBy(RoomsPrices.value, "rg_ext");
  return GP;
});

how to match every key values inside rg_ext here and then returned a grouped array. because here, i am getting all 4 objects in return rather than 2 objects with exact rg_ext.


Solution

  • Not sure if lodash can help you there, I would do it manually. Grouping works as always, i.e. for each item, go through the already created groups, and then either add it to an existing group or start a new one. You just have to check for a full object instead of a single field:

    const roomPrices = [
      {
        rg_ext: {
          class: 5,
          quality: 0,
          sex: 0,
          bathroom: 2,
          bedding: 3,
          family: 0,
          capacity: 2,
          club: 0,
        },
        room_name: "2 Bedrooms Double Suite (full double bed)",
        cost: 10000,
        priceid: 15464,
      },
      {
        rg_ext: {
          class: 3,
          quality: 0,
          sex: 0,
          bathroom: 2,
          bedding: 2,
          family: 0,
          capacity: 3,
          club: 0,
        },
        room_name: "3 Bedrooms Double Suite (full double bed)",
        cost: 14000,
        priceid: 12464,
      },
      {
        rg_ext: {
          class: 3,
          quality: 0,
          sex: 0,
          bathroom: 2,
          bedding: 2,
          family: 0,
          capacity: 3,
          club: 0,
        },
        room_name: "3 Bedrooms Double Suite (full double bed)",
        cost: 14000,
        priceid: 12464,
      },
      {
        rg_ext: {
          class: 5,
          quality: 0,
          sex: 0,
          bathroom: 2,
          bedding: 3,
          family: 0,
          capacity: 2,
          club: 0,
        },
        room_name: "2 Bedrooms Double Suite (full double bed)",
        cost: 16300,
        priceid: 36464,
      },
    ]
    
    const groupByObj = (arr, prop) => {
      const objectsMatch = (o1,o2) => {
        const k1 = Object.keys(o1)
        return k1.length === Object.keys(o2).length && k1.every(k => k in o2 && o1[k] === o2[k])
      }
      const res = []
      for(const item of arr){
        let group = res.find(g => objectsMatch(g[prop], item[prop]))
        if(!group){
          group = {[prop]: item[prop], items: []}
          res.push(group)
        }
        const {[prop]: _ , ...data} = item // just for readability of the example
        group.items.push(data)
      }
      return res
    }
    
    console.log(groupByObj(roomPrices, 'rg_ext'))

    In Vue, you need to unpack the ref first, but the rest works the same.