How to extract a particular element from an object based on key in typescript

Viewed 1540

I have a requirement where I need to extract an element/attribute from an JSON object based on a particular key. I am super confused here how to fetch.

{   "metadata":{
      "lastSyncTime":"2000-11-21T16:07:53",
      "dataFromDB":true
   },
   "allocationReports":[      {
         "allocatedUserCount":100,
         "healthGoalName":"Eat Healthier",
         "segments": [
            {segmentValue: "40-49", allocatedUserCount: 2}, 
            {segmentValue: "30-39", allocatedUserCount: 13},
            {segmentValue: "20-29", allocatedUserCount: 23}
         ]
      },
      {
         "allocatedUserCount":130,
         "healthGoalName":"Feel Happier",
         "segments": [
            {segmentValue: "40-49", allocatedUserCount: 20}, 
            {segmentValue: "30-39", allocatedUserCount: 3},
            {segmentValue: "20-29", allocatedUserCount: 53}
         ]
      },
  
      {
         "allocatedUserCount":150,
         "healthGoalName":"Quit Smoking",
         "segments": [
            {segmentValue: "40-49", allocatedUserCount: 19}, 
            {segmentValue: "30-39", allocatedUserCount: 1},
            {segmentValue: "20-29", allocatedUserCount: 22},
            {segmentValue: "10-19", allocatedUserCount: 47}
         ]
      }
   ],
   "overall":{
      "usersWithGoalCount":0,
      "registeredCount":500,
      "eligibleCount":280
   }
}

How can we extract the segments array based on healthgoalName. For example I have written a method which takes 'healthGoalName'(Let's say Quit Smoking) as argument. This method should return -

"segments": [
   {segmentValue: "40-49", allocatedUserCount: 19}, 
   {segmentValue: "30-39", allocatedUserCount: 1},
   {segmentValue: "20-29", allocatedUserCount: 22},
   {segmentValue: "10-19", allocatedUserCount: 47}
]

Thanks in advance.

3 Answers

I'm going to assume the JSON in the question is showing the content of an object called obj which is available in the context of the method called getSegments. If that is not the case, you'll need to provide that object to the method as a second argument.

function getSegments(healthGoalName)
{
    const allocationReport = obj.allocationReports.find(allocationReport => allocationReport.healthGoalName === healthGoalName);
    return allocationReport ? allocationReport.segments : null;
}

function getSegments(healthGoalName)
{
    const allocationReport = obj.allocationReports.find(allocationReport => allocationReport.healthGoalName === healthGoalName);
    return allocationReport ? allocationReport.segments : null;
}

const obj =
{
    "metadata":{
      "lastSyncTime":"2000-11-21T16:07:53",
      "dataFromDB":true
   },
   "allocationReports":[      {
         "allocatedUserCount":100,
         "healthGoalName":"Eat Healthier",
         "segments": [
            {segmentValue: "40-49", allocatedUserCount: 2}, 
            {segmentValue: "30-39", allocatedUserCount: 13},
            {segmentValue: "20-29", allocatedUserCount: 23}
         ]
      },
      {
         "allocatedUserCount":130,
         "healthGoalName":"Feel Happier",
         "segments": [
            {segmentValue: "40-49", allocatedUserCount: 20}, 
            {segmentValue: "30-39", allocatedUserCount: 3},
            {segmentValue: "20-29", allocatedUserCount: 53}
         ]
      },
  
      {
         "allocatedUserCount":150,
         "healthGoalName":"Quit Smoking",
         "segments": [
            {segmentValue: "40-49", allocatedUserCount: 19}, 
            {segmentValue: "30-39", allocatedUserCount: 1},
            {segmentValue: "20-29", allocatedUserCount: 22},
            {segmentValue: "10-19", allocatedUserCount: 47}
         ]
      }
   ],
   "overall":{
      "usersWithGoalCount":0,
      "registeredCount":500,
      "eligibleCount":280
   }
};

const segments = getSegments("Quit Smoking");
console.log({ segments });

It is a good idea to first type the structure of your data, something like:

interface Segment {
  segmentValue: string;
  allocatedUserCount: number;
}

interface AllocationReport {
  allocatedUserCount: number;
  healthGoalName: string;
  segments: Segment[];
}

interface Data {
  metadata: {
    lastSyncTime: string;
    dataFromDB: boolean;
  }
  allocationReports: AllocationReport[];
}

Then, you could code a function to get the segments as follows:

const search = (data: Data, healthGoalName: string): Segment[] | undefined => {
  for (const allocationReport of data.allocationReports) {
    if (allocationReport.healthGoalName === healthGoalName) {
      return allocationReport.segments;
    }
  }

  return undefined;
};

See notes in snippets

const dataObject = {"metadata":{
    "lastSyncTime":"2000-11-21T16:07:53",
    "dataFromDB":true
 },
 "allocationReports":[      {
       "allocatedUserCount":100,
       "healthGoalName":"Eat Healthier",
       "segments": [
          {segmentValue: "40-49", allocatedUserCount: 2}, 
          {segmentValue: "30-39", allocatedUserCount: 13},
          {segmentValue: "20-29", allocatedUserCount: 23}
       ]
    },
    {
       "allocatedUserCount":130,
       "healthGoalName":"Feel Happier",
       "segments": [
          {segmentValue: "40-49", allocatedUserCount: 20}, 
          {segmentValue: "30-39", allocatedUserCount: 3},
          {segmentValue: "20-29", allocatedUserCount: 53}
       ]
    },

    {
       "allocatedUserCount":150,
       "healthGoalName":"Quit Smoking",
       "segments": [
          {segmentValue: "40-49", allocatedUserCount: 19}, 
          {segmentValue: "30-39", allocatedUserCount: 1},
          {segmentValue: "20-29", allocatedUserCount: 22},
          {segmentValue: "10-19", allocatedUserCount: 47}
       ]
    }
 ],
 "overall":{
    "usersWithGoalCount":0,
    "registeredCount":500,
    "eligibleCount":280
 }
}

function findSegments(data,query) {
    //if data layer is an object
    if(!Array.isArray(data)){
        return Object.entries(data).reduce((output,[key,val]) => {
          //and if property is an array
          if(Array.isArray(val)){
              //run recursion 
              output = findSegments(val, query);
              return output; 
          }
          //otherwise ignore
          return output;
        },{})
    //if data layer is an array
    } else {
        return data.reduce((output,ele)=> {
            //and if healthGoalName matches query ignore
            if(ele.healthGoalName === query) {
                //extract segments
               output.segments = ele.segments;
               return output;       
            }
            //otherwise ignore
            return output;              
        }, {})
    } 
}
//pass original data object and healthGoalName query value
console.log(findSegments(dataObject,"Quit Smoking"))

Related