Woody
Woody

Reputation: 1787

How can I sum data in a multidimensional object in typescript?

I have the following code:

import { HttpClient } from "@angular/common/http";
import { Component, OnInit } from "@angular/core";
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";

@Component({
  styleUrls: ["./styles.scss"],
  templateUrl: "./template.html"
})
export class MyRouteData {
  MyDataObject: object;
  MyDataObjectTotals: object;

  constructor(private http: HttpClient) {}

  ngOnInit() {
    this.http
      .get("http://localhost:5000/MyRoute/GetMyData")
      .subscribe(response => {
        console.log(response);
        this.MyDataObject = response;
      });
  }
}

which stores the following data in the MyDataObject object:

{
  "Record1": {
    "CustomerName": "Obi Wan Kenobi",
    "TransactionDate": "2018-01-01",
    "IsNewCustomer": false,
    "ItemPuchased":"Speeder Polish 250ml",
    "QuantityPurchased":2,
    "SalesTotal":10.04
  },
  "Record2": {
    "CustomerName": "Darth Vader",
    "TransactionDate": "2018-01-02",
    "IsNewCustomer": false,
    "ItemPuchased":"Burn Cream 250ml",
    "QuantityPurchased":200000,
    "SalesTotal":7523840.84
  },
  "Record3": {
    "CustomerName": "Luke Skywalker",
    "TransactionDate": "2018-01-02",
    "IsNewCustomer": false,
    "ItemPuchased":"Power Converters",
    "QuantityPurchased":5,
    "SalesTotal":1324.02
  },
  "Record4": {
    "CustomerName": "Jabba the Hut",
    "TransactionDate": "2019-01-05",
    "IsNewCustomer": false,
    "ItemPuchased":"Dancing Slave Chick",
    "QuantityPurchased":1,
    "SalesTotal":150000.00
  }
}

Please note that the GetMyData endpoint is running a SQL query that returns a table. I have just represented the data as JSON here so it can be viewed easily. The columns the SQL query returns are CustomerName, TransactionDate, IsNewCustomer, ItemPuchased, QuantityPurchased, and SalesTotal.

I would like to store the totals of each column (where relevant) into another object (the MyDataObjectTotals in the code above).

I am able to total a single column with the following code:

var QuantityPurchasedColumn = MyDataObject.map(a => a.QuantityPurchased);
var QuantityPurchasedTotal = QuantityPurchasedColumn.reduce(function(a, b) {return a + b;});

Is there a generic method I can write to just give it an object (i.e MyDataObject) and it will return me an object with the following data (again, not a JSON string but an object with the CustomerName, TransactionDate, IsNewCustomer, ItemPuchased, QuantityPurchased, and SalesTotal columns):

{
    "CustomerName": null,
    "TransactionDate": null,
    "IsNewCustomer": null,
    "ItemPuchased":null,
    "QuantityPurchased": 200008,
    "SalesTotal": 7675174.90
}

Upvotes: 0

Views: 693

Answers (3)

Matt McCutchen
Matt McCutchen

Reputation: 30879

Based on your statement that you successfully used map, I'm assuming you intended MyDataObject to be an array instead of an object as shown in the question. You can iterate over the keys of the first record using a for-in loop and check, for each key, whether you want a sum or null.

var MyDataObject = [
  {
    "CustomerName": "Obi Wan Kenobi",
    "TransactionDate": "2018-01-01",
    "IsNewCustomer": false,
    "ItemPuchased": "Speeder Polish 250ml",
    "QuantityPurchased": 2,
    "SalesTotal": 10.04
  },
  {
    "CustomerName": "Darth Vader",
    "TransactionDate": "2018-01-02",
    "IsNewCustomer": false,
    "ItemPuchased": "Burn Cream 250ml",
    "QuantityPurchased": 200000,
    "SalesTotal": 7523840.84
  },
  {
    "CustomerName": "Luke Skywalker",
    "TransactionDate": "2018-01-02",
    "IsNewCustomer": false,
    "ItemPuchased": "Power Converters",
    "QuantityPurchased": 5,
    "SalesTotal": 1324.02
  },
  {
    "CustomerName": "Jabba the Hut",
    "TransactionDate": "2019-01-05",
    "IsNewCustomer": false,
    "ItemPuchased": "Dancing Slave Chick",
    "QuantityPurchased": 1,
    "SalesTotal": 150000.00
  }
];
type MyRecord = typeof MyDataObject[number];

var SumColumns: Partial<{ [K in keyof MyRecord]:
  MyRecord[K] extends number ? true : never }> = {
  "QuantityPurchased": true,
  "SalesTotal": true
};

var Sum = <{ [K in keyof MyRecord]: number | null }>{};
let columnName: keyof MyRecord;
for (columnName in MyDataObject[0]) { 
  Sum[columnName] = SumColumns[columnName]
    ? MyDataObject.map(a => <number>a[columnName]).reduce(function (a, b) { return a + b; })
    : null;
}

Upvotes: 1

Shadab Faiz
Shadab Faiz

Reputation: 2508

I can think of 2 different ways to solve this. 1. Iterate over the json keys.

var myObj = {

  "Record1": {
    "CustomerName": "Obi Wan Kenobi",
    "TransactionDate": "2018-01-01",
    "IsNewCustomer": false,
    "ItemPuchased":"Speeder Polish 250ml",
    "QuantityPurchased":2,
    "SalesTotal":10.04
  },
    "Record2": {
    "CustomerName": "Oobi",
    "TransactionDate": "2018-01-01",
    "IsNewCustomer": false,
    "ItemPuchased":"Speeder Polish 250ml",
    "QuantityPurchased":2,
    "SalesTotal":10.04
  },
};

for (var values in myObj) {
  console.log(myObj[values]['QuantityPurchased']);
}

2. Instead of sending json of Records, send array of Records

var myObj: Records[] = [

   {
    "CustomerName": "Obi Wan Kenobi",
    "TransactionDate": "2018-01-01",
    "IsNewCustomer": false,
    "ItemPuchased":"Speeder Polish 250ml",
    "QuantityPurchased":2,
    "SalesTotal":10.04
  },
 {
    "CustomerName": "Oobi",
    "TransactionDate": "2018-01-01",
    "IsNewCustomer": false,
    "ItemPuchased":"Speeder Polish 250ml",
    "QuantityPurchased":2,
    "SalesTotal":10.04
  },
];

myObj.forEach(myRecord => {
  // Do w/e you like.
});

Upvotes: 1

kashpatel
kashpatel

Reputation: 725

Did you try JSON.Parse(myObject) method? That will convert your JSON object into the JS object.

Upvotes: 1

Related Questions