skip to Main Content

I have a jsonArray with two embedded arrays with objects. I’m attempting to count "duty" parentId based on teams "value" as there is a one to one match. For example: Team A value 500 will have Meetings and Lunch duties and Team B will have Time Cards, Parking, and Breakfast duties.

{
"jsonArray":[
  {
     "teams":[
     
        {
           "text":"Team A",
           "id":1,
           "value":500,
           "parentId":333
        },
        {
           "text":"Team B",
           "id":2,
           "value":600,
           "parentId":444
        }
        
     ],
     "duty":[
     
        {
           "text":"Meetings",
           "id":11,
           "value":100,
           "parentId":500
        },
        {
           "text":"Lunch",
           "id":12,
           "value":101,
           "parentId":500
        },
        {
           "text":"Time Cards",
           "id":13,
           "value":102,
           "parentId":600
        },
        
        {
           "text":"Parking",
           "id":14,
           "value":103,
           "parentId":600
        
        },
         {
           "text":"Breakfast",
           "id":15,
           "value":104,
           "parentId":600
        }
     ]
  
  }
 ]
}

I’m getting the above json back correctly using Vue (Axios). Below is my method.
I was able to count using reduce but that was only just the first object in the array (teams),
with no linking to (duty). Is there a way to count by value and parentId since
they are in the same array…jsonArray.teams.value == jsonArray.duty.parentId ?

newJsonData() {
  var dutyCount = this.jsonArray.flatMap((item) => item.teams);

  let countValuesByKey = (arr, key) =>
    arr.reduce((r, c) => {
      r[c[key]] = (r[c[key]] || 0) + 1;
      return r;
    }, {});

  //returns numbers only 
  let countValue = (arr, key, value) =>
    arr.filter((x) => x[key] === value).length;

  console.debug("dutyCount", countValuesByKey(dutyCount, "text"));

  return dutyCount;
},

Expected Result:

{
  "Team A": 2,
  "Team B": 3
}

2

Answers


  1. You’re not too far off with your attempt – while there are a few ways to do this, the easiest way (IMO) is to stick with reduce().

    In the function below, I use it twice: first to build an object map of team IDs to their text names, then I use a second reduce() call on the duty array to count instances of that team’s ID:

    const jsonResponse = {
      "jsonArray": [{
        "teams": [
    
          {
            "text": "Team A",
            "id": 1,
            "value": 500,
            "parentId": 333
          },
          {
            "text": "Team B",
            "id": 2,
            "value": 600,
            "parentId": 444
          }
    
        ],
        "duty": [
    
          {
            "text": "Meetings",
            "id": 11,
            "value": 100,
            "parentId": 500
          },
          {
            "text": "Lunch",
            "id": 12,
            "value": 101,
            "parentId": 500
          },
          {
            "text": "Time Cards",
            "id": 13,
            "value": 102,
            "parentId": 600
          },
    
          {
            "text": "Parking",
            "id": 14,
            "value": 103,
            "parentId": 600
    
          },
          {
            "text": "Breakfast",
            "id": 15,
            "value": 104,
            "parentId": 600
          }
        ]
    
      }]
    };
    
    function processJsonResponse(jsonResponse) {
      return jsonResponse['jsonArray'].map(cv => {
        var teams = cv['teams'].reduce((acc, team) => {
          acc[team['value']] = team['text'];
          return acc;
        }, {});
        return cv['duty'].reduce((acc, duty) => {
          acc[teams[duty['parentId']]] = acc[teams[duty['parentId']]] ? acc[teams[duty['parentId']]] + 1 : 1;
          return acc;
        }, {});
      });
    };
    
    console.log(processJsonResponse(jsonResponse));

    This code is also built to support future instances where jsonResponse['jsonArray'].length > 1 by using map() on jsonResponse['jsonArray'] – however all you need to do to match exactly the expected output you’ve prescribed in your post is to tack the [0] on to your call to processJsonResponse(), i.e. processJsonResponse(jsonResponse)[0].

    Login or Signup to reply.
  2. An Array.reduce with proper indexing to both array will solve your issue.

    A working example is added below

    const response = {
      jsonArray: [
        {
          teams: [
            { text: "Team A", id: 1, value: 500, parentId: 333 },
            { text: "Team B", id: 2, value: 600, parentId: 444 },
          ],
          duty: [
            { text: "Meetings", id: 11, value: 100, parentId: 500 },
            { text: "Lunch", id: 12, value: 101, parentId: 500 },
            { text: "Time Cards", id: 13, value: 102, parentId: 600 },
            { text: "Parking", id: 14, value: 103, parentId: 600 },
            { text: "Breakfast", id: 15, value: 104, parentId: 600 },
          ],
        },
      ],
    };
    const result = response.jsonArray[0].duty.reduce((acc, curr) => {
      const teamName = response.jsonArray[0].teams.find(
        (team) => team.value === curr.parentId
      );
      if (teamName && teamName.text) {
        acc[teamName.text] = acc[teamName.text] ? ++acc[teamName.text] : 1;
      }
      return acc;
    }, {});
    console.log(result);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search