Search code examples
javascriptjsonlodashchaining

Lodash chaining?


I have a JSON object which looks like that:

{
      "ReceiptNumber": 2129,
      "ReceiptResult": 1,
      "ReceiptAmount": "6756",
      "ReceiptData": [
        {
          "LineNum": "JonSnow",
          "Data": "Standard data for Jon Snow"
        },
        {
          "LineNum": "HarryPotter",
          "Data": "Standard data for Harry Potter"
        },
        {
          "LineNum": "MickyMouse",
          "Data": "Standard data for Micky Mouse"
        }
      ],
      "ReceiptReference": "22e06e66-e711-bd14-7874a-002219649f24"
}

I'm trying to convert it into:

{
    "receiptNumber": 2129,
    "receiptResult": 1,
    "receiptAmount": "6756",
    "receiptData": {
        "jonSnow": "Standard data for Jon Snow",
        "harryPotter": "Standard data for Harry Potter",
        "mickyMouse": "Standard data for Micky Mouse"
    },
    "receiptReference": "22e06e66-e711-bd14-7874a-002219649f24"
}

The methods that I'm suing:

  getFromReceipt(result): void {
    result.ReceiptData = _.assign({}, ...result.ReceiptData.map(el => {
      return { [_.camelCase(el.LineNum)]: el.Data }
    }));

    this.camelCaseAllKeys(result);
  }

  camelCaseAllKeys(result) {
    return _.mapKeys(result, (v, k) => _.camelCase(k.toString()));
  }

Is there any way to simplify that methods and eventually do everything in one function through chaining?


Solution

  • This is too long for a comment.

    You are conflating multiple concerns here in one function:

    1. flatten the ReceiptData
    2. camelcase the keys

    It is not clear that those things should be in the same function: while it's shorter code that's a false economy. Once you run it through minifier + gzip the difference is negligible, and while shorter code is generally easier to read conflating different concerns makes it harder. Unless your dataset is truly massive (in which case why are you processing it client-side?) impact on runtime performance will be negligible.

    So I would recommend something more like this:

    let data = howeverYouGotTheData;
    let flattenReceiptData = o => {
      o.ReceiptData = o.ReceiptData.reduce((acc, record) => {
        acc[_.camelCase(record.lineNum)] = record.Data;
        return acc;
      }, {});
      return o;
    };
    
    let camelCaseKeys = o => {
      return Object.entries(o).reduce((acc, [k, v]) => {
        acc[_.camelCase(k)] = v;
        return acc;
      }, {});
    };
    
    // _.flow is lodash's implementation of left composition
    let flattenAndCase = _.flow(flattenReceiptData, camelCaseKeys);
    
    let result = flattenAndCase(data);
    

    Now the concerns are properly separated, everything is clearly named and easy to read, and so on. If you really want to golf this down you could use some standard tricks like this:

    let cc = _.camelCase;
    let flattenRD = o => (o.ReceiptData = o.ReceiptData.reduce((a, x) => (a[cc(x.lineNum)] = x.Data, a), {}));
    

    etc. etc. I've used the comma operator to squish the assignment and return into one expression avoiding the need for Object.assign.