Update property of object inside Array

77 views Asked by At

On the click of a button the data in fruitData array gets added to another array called history. I want the property 'bins' inside history to update whenever the properties: "kultivar", "blokNommer" and "year" match with the objects added from fruitData. (number inside bins property needs to be added together if there is a match)

for example this:

[
{datum: "2020-04-08", kultivar: "bc", ha: "5", blokNommer: "1", bins: "20", year: "2020"}, 
{datum: "2020-04-08", kultivar: "bc", ha: "5", blokNommer: "1", bins: "20", year: "2020"}
]

should equal this (bins: 40):

[
 {datum: "2020-04-08", kultivar: "bc", ha: "5", blokNommer: "1", bins: "40", year: "2020"}
]

My code:

let fruitData = [{
    datum: "2020-04-08",
    kultivar: "bc",
    ha: "5",
    blokNommer: "1",
    bins: "20",
    year: "2020"
  },
  {
    datum: "2020-09-18",
    kultivar: "wb",
    ha: "5",
    blokNommer: "1",
    bins: "5",
    year: "2020"
  },
  {
    datum: "2020-03-09",
    kultivar: "bc",
    ha: "5",
    blokNommer: "1",
    bins: "20",
    year: "2020"
  },
  {
    datum: "2020-04-08",
    kultivar: "bc",
    ha: "5",
    blokNommer: "1",
    bins: "20",
    year: "2020"
  }
]

historyButton.addEventListener('click', () => {
  addToHistory(fruitData)
})



function addToHistory(elements) {
  for (let elem in elements) {
    history = [...history, elements[elem]];
  }
  sortHistory()
}



function sortHistory() {
  let newHistory = [];
  history.forEach(function(item, index) {
    if (newHistory.length === 0) {
      newHistory.push(item)
    } else {
      newHistory.forEach(function(itm, idx) {
        if (item.year === itm.year && item.kultivar === itm.kultivar && item.blokNommer ===
          itm.blokNommer) {
          item.bins = item.bins + itm.bins
        } else {
          newHistory.push(item)
        }
      })
    }
  })
  console.log(newHistory)
}

This does not give the output I am looking for. Have tried reduce method as well with no luck. Would appreciate any help!

3

There are 3 answers

0
zb22 On BEST ANSWER

You need to iterate the original array, and use find() to retrieve the existing item in the history array which match to kultivar, blokNommer and year in order to access bins and update it.

Note: It's also important to convert bins by Number() as its string in your example, and after that convert it back to string.

const arr = [
{datum: "2020-04-08", kultivar: "bc", ha: "5", blokNommer: "1", bins: "20", year: "2020"}, 
{datum: "2020-09-18", kultivar: "wb", ha: "5", blokNommer: "1", bins: "5", year: "2020"}, 
{datum: "2020-03-09", kultivar: "bc", ha: "5", blokNommer: "1", bins: "20", year: "2020"}, 
{datum: "2020-04-08", kultivar: "bc", ha: "5", blokNommer: "1", bins: "20", year: "2020"}
]

const history = [];

arr.forEach(item => {
  const found = history.find(({ kultivar, blokNommer, year }) => 
    kultivar === item.kultivar && blokNommer === item.blokNommer && year === item.year)
  
  if(found) {
    found.bins = (Number(found.bins) + Number(item.bins)).toString();
  } else {
    history.push(item);
  }
});

console.log(history);

find() Number()

0
Prakhar Londhe On

The problem with your implementation is that you are changing theitm.bins. Array.forEach creates a copy of each element when you traverse it, so any value you change for itm wouldn't reflect in the actual array. Hence you are provided with the idx if you want to change the actual element.

Also, you are using + for adding strings, not integers. You need to convert it to integers first to get the desired result.

The final code should be:

function sortHistory(){
        let newHistory = [];
        history.forEach(function(item, index){
            if(newHistory.length === 0){
                newHistory.push(item)
            } else{
                newHistory.forEach(function(itm, idx){
                    if(item.year === itm.year && item.kultivar === itm.kultivar && item.blokNommer === 
                       itm.blokNommer){
                        newHistory[idx].bins = parseInt(item.bins) + parseInt(itm.bins);
                    }else{
                        newHistory.push(item)
                    }
                })
            }
        })
        console.log(newHistory);
history = newHistory;}
0
ironCat On

If your fruitData array not very big you can try use iterating over elements and searching indexOf the entire array cast to a string by JSON.stringify
But if the array is large then the code is not optimal


const fruitData = [
  {datum: "2020-04-08", kultivar: "bc", ha: "5", blokNommer: "1", bins: "20", year: "2020"}, 
  {datum: "2020-09-18", kultivar: "wb", ha: "5", blokNommer: "1", bins: "5", year: "2020"}, 
  {datum: "2020-03-09", kultivar: "bc", ha: "5", blokNommer: "1", bins: "20", year: "2020"}, 
  {datum: "2020-04-08", kultivar: "bc", ha: "5", blokNommer: "1", bins: "20", year: "2020"}]
  
const sortHistory = (myArray) => Object.keys(myArray).reduce((accum, item) => {
  const currItem = JSON.stringify(myArray[item])
  const allArr = JSON.stringify(accum)
  return (allArr.indexOf(currItem) >= 0) ? accum : accum.concat(myArray[item])
}, [])   


console.log(sortHistory(fruitData))