Search code examples
javascriptjsonunderscore.jslodash

GroupBy with Multiple Columns using Lodash or Underscore in Javascript


Getting Problem while converting JSON structure. My JSON Structure is as below.

const member = [{
    memberId: 4,
    memberName: 'ABC',
    age: 22,
    eventId: 5,
    eventName: 'Dance'
  },
  {
    memberId: 4,
    memberName: 'ABC',
    age: 22,
    eventId: 6,
    eventName: 'Music'
  },
  {
    memberId: 4,
    memberName: 'ABC',
    age: 22,
    eventId: 7,
    eventName: 'FootBall'
  },
  {
    memberId: 5,
    memberName: 'PQR',
    age: 24,
    eventId: 6,
    eventName: 'Music'
  },
  {
    memberId: 5,
    memberName: 'PQR',
    age: 24,
    eventId: 5,
    eventName: 'Dance'
  },
]

Here I have two members with associated events. And I want to convert JSON as follows.

const member = [
  {
    memberId: 4,
    memberName: 'ABC',
    age: 22,
    events: [
      {
        id: 5,
        name: 'Dance'
      },
      {
        id: 6,
        name: 'Music'
      },
      {
        id: 7,
        name: 'FootBall'
      }
    ]
  },
  {
    memberId: 5,
    memberName: 'PQR',
    age: 24,
    events: [
      {
        id: 6,
        name: 'Music'
      },
      {
        id: 5,
        name: 'Dance'
      }
    ]
  }
]

I tried creating the structure using below code but it doesn't provide as the desired output. It just creates two Key-Value pair.

var result = _.chain(member)
            .groupBy("memberId")
            .pairs()
            .map(function(currentItem) {
                return _.object(_.zip(["memberId", "events"], currentItem));
            })
            .value();

I don't know how to add other values of JSON in the hierarchy.


Solution

  • After you group the items, map them. Take the 1st item of each group, and remove the event properties, and spread it. To get the the events data, map the group's items and take only the relevant event properties:

    const member = [{"memberId":4,"memberName":"ABC","age":22,"eventId":5,"eventName":"Dance"},{"memberId":4,"memberName":"ABC","age":22,"eventId":6,"eventName":"Music"},{"memberId":4,"memberName":"ABC","age":22,"eventId":7,"eventName":"FootBall"},{"memberId":5,"memberName":"PQR","age":24,"eventId":6,"eventName":"Music"},{"memberId":5,"memberName":"PQR","age":24,"eventId":5,"eventName":"Dance"}]
    
    const result = _(member)
      .groupBy('memberId')
      .map(group => ({
        ..._.omit(_.head(group), ['eventId', 'eventName']),
        events: _.map(group, o => ({ id: o.eventId, name: o.eventName }))
      }))
      .value();
      
    console.log(result)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

    And the same solution using underscore:

    const member = [{"memberId":4,"memberName":"ABC","age":22,"eventId":5,"eventName":"Dance"},{"memberId":4,"memberName":"ABC","age":22,"eventId":6,"eventName":"Music"},{"memberId":4,"memberName":"ABC","age":22,"eventId":7,"eventName":"FootBall"},{"memberId":5,"memberName":"PQR","age":24,"eventId":6,"eventName":"Music"},{"memberId":5,"memberName":"PQR","age":24,"eventId":5,"eventName":"Dance"}]
    
    const result = _.chain(member) // <- change for underscore 
      .groupBy('memberId')
      .map(group => ({
        ..._.omit(_.head(group), ['eventId', 'eventName']),
        events: _.map(group, o => ({ id: o.eventId, name: o.eventName }))
      }))
      .value();
      
    console.log(result)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore.js"></script>