How to loop through objects and count unique values of key?

Viewed 65

I have logs of json files which are objects that look like

{
  "logs": [
    {
      "id": "12321321321321",
      "email": "test@email.com",
      "message": "ahahaha"
    },
    {
      "id": "12321321312",
      "email": "test@email.com",
      "message": "hahahaha."
    },
   "id": "12321321321"
}

I need to return a new object that contains

{
    "hello_id": outer id of the json file,
    "array": [
       
       {
        "email": "test@me.com",
        "total": 2
       }
      ]
    }

So far I am looping through the json files and have

    jsonsInDirectory.forEach((file) => {
  const fileData = fs.readFileSync(path.join("./logs", file), "utf8");
  const jsonData = JSON.parse(fileData);
  }
});

The key is "logs" and "id" and the values are the objects in the "logs" and the value of "id"

How can I count and return a new object at the same time?

3 Answers

You can try this approach: make a hash object that counts emails. Then just map it to an array of objects.

const data = {
  logs: [{
      id: "89004ef9-e825-4547-a83a-c9e9429e8f95",
      email: "noah.sanchez@me.com",
      message: "successfully handled skipped operation."
    },
    {
      id: "89004ef9-e825-4547-a83a-c9e9429e8f95",
      email: "noah.sanchez@me.com",
      message: "successfully handled skipped operation."
    },
    {
      id: "89004ef9-e825-4547-a83a-c9e9429e8f95",
      email: "noname@me.com",
      message: "successfully handled skipped operation."
    }],
  id: "56f83bed-3705-4115-9067-73930cbecbc0",
};

const emails = data.logs.reduce((acc, { email }) => {
  acc[email] = (acc[email] ?? 0) + 1;

  return acc;
}, {});

const tally = Object.entries(emails)
  .map(([email, total]) => ({ email, total }));
  
const result = { logs_id: data.id, tally };

console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0 }

To solve this problem with the most time efficiency, you can create a tally object by firstly creating a map of the occurences of each mail with the email as the key and no of occurences as the value, since this will take constant (O(1)) time to execute, afterwhich you can create the tally array from the map as given below

output = []
jsonsInDirectory.forEach((file) => {
  const fileData = fs.readFileSync(path.join("./logs", file), "utf8");
  const jsonData = JSON.parse(fileData);
  var map = {}
  jsonData.logs.forEach((log) => {
    if(log.email in map){
        map[log.email] += 1
    }
    else {
        map[log.email] = 1
    }
  });
  var tally = []
  for(var email in map){
    tally.push({email: email, total: map[email]})
  }
  output.push({logs_id: jsonData['id'], tally: tally});
})
Related