-3

I have a file with 1000s of json rows like below. Im having difficulties locating a specific key in the array. example json:

    {"connection":"98374"
     ,"db":"8",
     ,"timestamp":"159905411631"
     ,"event":"DataCatch"
     ,"data":[{"key":"ruleid","value":"111"}
             ,{"key":"responseid","value":"155-response-4"}
             ,{"key":"responsetype","value":"Capture"}
             ,{"key":"reason","value":"ClientVisit"}
             ,{"key":"subreason","value":""}
             ,{"key":"score","value":"0.00"} 
             ,{"key":"comment","value":""}]
    }

I need to be able to find the "reason" key in the "data" array and replace the "value" with "test". The "data" array doesn't always appear on every json row, only when the "event" "dataCatch" is present.

I can parse it into a variable but I can only call the "data" array as a whole. Any ideas how to target specific values in an array?

Having a little trouble with this in Typescript.

dragonfury2
  • 375
  • 5
  • 20

2 Answers2

2

There are any number of ways to go about this, but here's one.

First, parse your JSON into an array of objects. Each element of the array will then look something like this:

{
  connection: '98374',
  db: '8',
  timestamp: '159905411631'
  event: 'DataCatch',
  data: [
    { key: 'ruleid', value: '111' },
    { key: 'responseid', value: '155-response-4' },
    { key: 'responsetype', value: 'Capture' },
    { key: 'reason', value: 'ClientVisit' },
    { key: 'subreason', value: '' },
    { key: 'score', value: '0.00' },
    { key: 'comment', value: '' },
  ],
}

Let's call our array of objects allData, so we can refer to it later.

Now we can begin our "surgery". We'll work from the inside-out, first looking at what needs to be done to a specific entry in an element's data array.

Here's a function that will do just what we need:

function updateReason(entry) {
  if (entry.key === 'reason') {
    return { ...entry, value: 'test' };
  } else {
    return entry;
  }
}

This function checks if the provided entry has a key with a value of 'reason', and -- if so -- returns a new entry that is identical to the provided one except its value is 'test'.

How can we use this to update an entire data array (in an entry that has data, that is)? We simply delegate the work to our dear friend map:

function updateData(data) {
  // or simply `data.map(updateEntry);`
  return data.map(entry => updateEntry(entry));
}

We're slowly working our way "outwards". What about updating an entire entry in our big allData array (which may or may not contain data)?

// I've called such an entry a "collection", because I already used the name
// "entry" above :(
// A "collection" is just an entry in the big `allData` array.
function updateCollection(collection) {
  if (collection.event === 'DataCatch') {
    return {
       ...collection,                     // Leave everything else the way it is
       data: updateData(collection.data), // But update the `data` array
    };
  } else {
    return collection;
  }
}

So close. The last thing we need to do is apply this transformation to every element of our parsed allData array:

// or `allData.map(updateCollection);`
const updatedData = allData.map(collection => updateCollection(collection));

Also:

Q: Wouldn't it be cheaper to mutate the entry?

A: It would be cheaper, but not that much cheaper, due to a large amount of "structural sharing" that occurs here. I would recommend this approach unless you either need to mutate your input for some reason, or performance requirements demand it.

William Lewis
  • 537
  • 4
  • 9
1

You need to map over the data key in your data variable like this.

data.data = data.data.map((item) => {
  if (item.key === "reason") {
    item.value = "test";
  }
  return item;
});

the data key is an array of values, so you need to loop through it and compare the value of the key property to the value you are looking for, if it matches then you can update the value property

https://codesandbox.io/s/angry-shirley-1gh83?file=/src/index.ts:666-782

kyle
  • 2,563
  • 6
  • 22
  • 37