Zigrivers
Zigrivers

Reputation: 409

Need help using lodash to reform an array with new structure

I have this sample data that is returned from an API that I am trying to reform into an array with a sub-array of grouped objects. The raw data from the API looks like this:

[
    {
        "InsightId": 314,
        "Classification": "Advantage",
        "AttributeId": 14958,
        "InsightAttribute": "Implementation speed",
        "AttributeType": "Product Criterion"
    },
    {
        "InsightId": 314,
        "Classification": "Advantage",
        "AttributeId": 14976,
        "InsightAttribute": "Understanding your needs",
        "AttributeType": "Sales Criterion"
    },
    {
        "InsightId": 315,
        "Classification": "Disadvantage",
        "AttributeId": 17691,
        "InsightAttribute": "Poor alignment with needs",
        "AttributeType": "Product Criterion"
    }
]

I want to group by the InsightId and create an object out of three of the properties: AttributeId, InsightAttribute, AttributeType.

And have the final array take the form of the following:

[
    {
        "InsightId": 314,
        "Classification": "Advantage",
        "Attributes" : [
            {
                "AttributeId": 14958,
                "InsightAttribute": "Implementation speed",
                "AttributeType": "Product Criterion"
            },

            {
                AttributeId": 14976,
                "InsightAttribute": "Understanding your needs",
                "AttributeType": "Sales Criterion"
            }
        ]
    },
    {
        "InsightId": 315,
        "Classification": "Disadvantage",
        "Attributes" : [
            {
                "AttributeId": 17691,
                "InsightAttribute": "Poor alignment with needs",
                "AttributeType": "Product Criterion"
            }
        ]   
    }
]

I'm new to Lodash and I've already spent hours going down a few rabbit holes that haven't worked out. I've realized it's time to turn to the experts. Any advice on how to get to the final result I've showed above?

Thanks for your help!

Upvotes: 0

Views: 197

Answers (2)

user229044
user229044

Reputation: 239302

The most useful part of lodash here is pick, which allows you to selectively slice out some properties of an object by name.

Basically, instead of this:

obj1 = {
  name: obj2.name
  age: obj2.age
  size: obj2.size
}

You may simply do

obj1 = _.pick(obj1, 'name', 'age', 'size')

You can just iterate over your data, building up your required structure in an object for easy lookup by InsightId, and then convert it to the flat array you're after with _.values afterwards.

    data = [
        {
            "InsightId": 314,
            "Classification": "Advantage",
            "AttributeId": 14958,
            "InsightAttribute": "Implementation speed",
            "AttributeType": "Product Criterion"
        },
        {
            "InsightId": 314,
            "Classification": "Advantage",
            "AttributeId": 14976,
            "InsightAttribute": "Understanding your needs",
            "AttributeType": "Sales Criterion"
        },
        {
            "InsightId": 315,
            "Classification": "Disadvantage",
            "AttributeId": 17691,
            "InsightAttribute": "Poor alignment with needs",
            "AttributeType": "Product Criterion"
        }
    ]
    
    hash = {}
    
    data.forEach(function (r) {
      if (!hash[r.InsightId])
        hash[r.InsightId] = _.merge(
          _.pick(r, 'InsightId', 'Classification'), {Attributes: []}
        );

      hash[r.InsightId].Attributes.push(_.pick(r, "AttributeId", "InsightAttribute", "AttributeType"))
    });


    output = _.values(hash);
    

    console.log(output);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.js"></script>

Upvotes: 0

dandavis
dandavis

Reputation: 16726

you can use reduce() to loop and build up a new response:

  _.values( _.reduce([{
    "InsightId": 314,
    "Classification": "Advantage",
    "AttributeId": 14958,
    "InsightAttribute": "Implementation speed",
    "AttributeType": "Product Criterion"
  }, {
    "InsightId": 314,
    "Classification": "Advantage",
    "AttributeId": 14976,
    "InsightAttribute": "Understanding your needs",
    "AttributeType": "Sales Criterion"
  }, {
    "InsightId": 315,
    "Classification": "Disadvantage",
    "AttributeId": 17691,
    "InsightAttribute": "Poor alignment with needs",
    "AttributeType": "Product Criterion"
  }], function(a, b) {

    // create a new array for common items under InsightId:
    var temp=a[b.InsightId] = a[b.InsightId] || {
        InsightId: b.InsightId,
        Classification: b.Classification,
        Attributes: []
    };

    // push current attribs into collection under InsightId:
    temp.Attributes.push({
        AttributeId: b.AttributeId,
        InsightAttribute: b.InsightAttribute,
        AttributeType: b.AttributeType
    });
    return a;
  }, {}));

which gives back:

[
    {
        "InsightId": 314,
        "Classification": "Advantage",
        "Attributes": [
            {
                "AttributeId": 14958,
                "InsightAttribute": "Implementation speed",
                "AttributeType": "Product Criterion"
            },
            {
                "AttributeId": 14976,
                "InsightAttribute": "Understanding your needs",
                "AttributeType": "Sales Criterion"
            }
        ]
    },
    {
        "InsightId": 315,
        "Classification": "Disadvantage",
        "Attributes": [
            {
                "AttributeId": 17691,
                "InsightAttribute": "Poor alignment with needs",
                "AttributeType": "Product Criterion"
            }
        ]
    }
]

there may be a slightly simpler way to gather the attribs, but with only 3 keys, hard-coding is not too cumbersome.

Upvotes: 1

Related Questions