Search code examples
javascriptlodash

Using lodash to transform data into object properties instead of a collection


following up on my previous question about transforming data using lodash, this time i require output to be an object properties instead of being a collection. I appreciate the help and if someone can also guide me where to begin properly so i have a better understanding of these concepts

Sample Data

var sample = [{
    "changeType": 1,
    "type": "changeAccount",
    "updated": {
      "id": 71,
      "company": 124201,
      "user": 8622
    }
  },
  {
    "changeType": 2,
    "type": "changeAccount",
    "updated": {
      "id": 70,
      "company": 124201,
      "user": 8622
    }
  },
  {
    "changeType": 1,
    "type": "changeproduct",
    "updated": {
      "id": 15,
      "company": 124201,
      "user": 8622
    }
  }
]

// what I tried
var result = _.mapValues(_.groupBy(sample, "type"), x => x.map(y => _.omit(y, "changeType")));

console.log(result);

Expected Result

var output = {
    "ChangeAccount": {

        "changeTypes":
            {
                "add": [{}], //type 1

                "remove": [{}] //type 2


            }
    },

    "ChangeProduct":{

        "changeTypes":
            {
                "add": [{}], //type 1

                "remove": [{}] //type 2  will be empty in this case
            }
    }
}

Previous Question Answer

const fn = arr =>
  map(groupBy(arr, 'type'), (group, type) => ({ // group and map to array of objects
    type,
    ...mapValues( // spread after mapping the values to extract updated
      groupBy(group, 'changeType'), // group again by changeType
      items => items.map(item => pick(item, 'updated') // extract the updated from each item
    ))
  }))

**Previous Answer Output **

 [
    {
        [
            {
                "updated": {
                    "id": 71,
                    "company": 124201,
                    "user": 8622
                }
            }
            ],
        [
            {
                "updated": {
                    "id": 70,
                    "company": 124201,
                    "user": 8622
                }
            }
            ],
        "type": "changeAccount"
    },
        {
            [
                {
                    "updated": {
                        "id": 15,
                        "company": 124201,
                        "user": 8622
                    }
                }
                ],
            "type": "changeproduct"
        }

Solution

  • I will say that you are not forced to use lodash, and that you can make this with just plain javascript. But, since you have required to use lodash, here is an easy way. You can simplify it depending on how hard your requirements are.

    const omitChangeType = ({changeType, ...rest}) => rest // this is just ES6, don't need lodash for this
    
    _.mapValues(
        _.groupBy(sample, "type"), 
        (x) => ({ 
            changeTypes: { 
                add: x.filter(_.matches({ changeType: 1 })).map(omitChangeType), 
                remove: x.filter(_.matches({ changeType: 2 })).map(omitChangeType)
            }})
        )
    

    What I like about this solution is that you have an idea of how the final structure will look like.

    Output:

    {
      "changeAccount": {
        "changeTypes": {
          "add": [
            {
              "type": "changeAccount",
              "updated": {
                "id": 71,
                "company": 124201,
                "user": 8622
              }
            }
          ],
          "remove": [
            {
              "type": "changeAccount",
              "updated": {
                "id": 70,
                "company": 124201,
                "user": 8622
              }
            }
          ]
        }
      },
      "changeproduct": {
        "changeTypes": {
          "add": [
            {
              "type": "changeproduct",
              "updated": {
                "id": 15,
                "company": 124201,
                "user": 8622
              }
            }
          ],
          "remove": []
        }
      }
    }
    

    In my solution I'm using a bit of ES destructuring, which is a very handy feature if you are going to work with data modification like this. Take a look at this if you are not familiar with it. Also, I'm not sure if your intention is to just omit changeType or if you want to extract the updated part of each object. If you want to just pick the updated property of each object, just change every appearance by the following function name, and add this function declaration:

    const pickUpdated = ({updated}) => updated
    

    So instead of .map(omitChangeType) you do .map(pickUpdated)

    In that case the output will look like

    {
      "changeAccount": {
        "changeTypes": {
          "add": [
            {
              "id": 71,
              "company": 124201,
              "user": 8622
            }
          ],
          "remove": [
            {
              "id": 70,
              "company": 124201,
              "user": 8622
            }
          ]
        }
      },
      "changeproduct": {
        "changeTypes": {
          "add": [
            {
              "id": 15,
              "company": 124201,
              "user": 8622
            }
          ],
          "remove": []
        }
      }
    }
    

    Feel free to comment if you have any doubt