How to properly filter an object that has an array of objects

71 Views Asked by At

I'm trying to filter an array to get only what I want and I have tried with filter and reduce, but I was not able to make it fully work. I'm trying to get only the objects that has "System.State" with an "oldValue" and a "newValue"

const data = {
  "value": [
    {
      "id": 23,
      "fields": {
        "System.State": {
          "oldValue": "Forecasted",
          "newValue": "Done"
        }
      }
    },
  ]
}

The problem is that value array contains several objects that may NOT have "System.State" and some that have "System.State" but only with "newValue", instead of "oldValue" and "newValue", so I'm receiving a lot of undefined errors and I really don't know how to treat these situations.

This is a example that dont have "System.State" and another one that have "System.State" but with "newValue" only:

const data = {
  "value": [
    {
      "id": 23,
      "fields": {
        "System.State": {
          "oldValue": "Forecasted",
          "newValue": "Done"
        }
      }
    },
    {
      "id": 24,
      "fields": {
        "System.State": {
          "newValue": "New"
        }
      }
    },
    {
      "id": 25,
      "fields": {
        "System.AuthorizedDate": { // This is only an example of an object that does not have System.State
          "newValue": "2020-03-13T14:14:37.1Z"
        }
      }
    },
  ]
}

I'm using TFS API if anyone wants to know. This is what I have tried using filter:

data.value.fields.filter(status => status.fields['System.State'].oldValue === 'Forecasted' && status.fields['System.State'] === 'Done')

And this was using reducer:

  const filter = data.value.reduce((c, n) => {
    const HasNewAndOldValue = c.fields['System.State'].oldValue === 'Forecasted' && c.fields['System.State'].newValue === 'Done';
    if (c.fields['System.State'] && HasNewAndOldValue) {
      return c;
    }
    c.push(n); 
  }, [])
  console.log(data.value.fields && filter);

What I'm doing wrong? Btw, I'm using ['System.State'] because I can't access an object property that has a dot.

3

There are 3 best solutions below

2
Typing On BEST ANSWER

In your filter example, replace data.value.fields.filter() with data.value.filter(), because data.value is an array.

const data = {
  "value": [
    {
      "id": 23,
      "fields": {
        "System.State": {
          "oldValue": "Forecasted",
          "newValue": "Done"
        }
      }
    },
    {
      "id": 24,
      "fields": {
        "System.State": {
          "newValue": "New"
        }
      }
    },
    {
      "id": 25,
      "fields": {
        "System.AuthorizedDate": { // This is only an example of an object that does not have System.State
          "newValue": "2020-03-13T14:14:37.1Z"
        }
      }
    },
  ]
}

console.log(
  data.value.filter((item) => {
    const fields = item.fields || {};
    const state = fields['System.State'];
    if (!state) {
      return false;
    }

    return state.oldValue && state.newValue;
  })

);

2
Ele On

This data.value.fields is undefined, you should access the property fields through each object within the property value.

const data = {  "value": [    {      "id": 23,      "fields": {        "System.State": {          "oldValue": "Forecasted",          "newValue": "Done"        }      }    },    {      "id": 24,      "fields": {        "System.State": {          "newValue": "New"        }      }    },    {      "id": 25,      "fields": {        "System.AuthorizedDate": {          "newValue": "2020-03-13T14:14:37.1Z"        }      }    }  ]};

console.log(data.value.filter(({fields: {"System.State": state}}) => {
  return state && state.oldValue === "Forecasted" && state.newValue === "Done";
}));

0
terrymorse On

Just filter the value property to include only the array elements that contain:

"fields": {
  "System.State": {
    "oldValue": "anything",
    "newValue:": "anything"
  }
}

function filterData(data) {
  let filteredValue = data.value.filter(el => {
    return el.fields["System.State"] &&
      el.fields["System.State"].oldValue &&
      el.fields["System.State"].newValue;
  });
  return { value: filteredValue };
}

const data = {
  "value": [
    {
      "id": 23,
      "fields": {
        "System.State": {
          "oldValue": "Forecasted",
          "newValue": "Done"
        }
      }
    },
    {
      "id": 24,
      "fields": {
        "System.State": {
          "newValue": "New"
        }
      }
    },
    {
      "id": 25,
      "fields": {
        "System.AuthorizedDate": {
        // This is only an example of an object that does not have System.State
          "newValue": "2020-03-13T14:14:37.1Z"
        }
      }
    },
  ]
}

let filtData = filterData(data);
document.getElementById('results').innerHTML =
  JSON.stringify(filtData, null, 2);
Filtered data:<br/>
<pre id="results"></pre>