Search code examples
javascriptarraysforeachjavascript-objects

Javascript - Add new object into array of objects


please. I have a cycle with fiance balances. It's an array of objects like:

export const balances = [
type: types.outgoing,
    date: 20220410,
    amount: 282.12,
    category: categories.installments,
    source: 'Debit account',
    destination: 'Leasing company',
  },
  {
    type: types.income,
    date: 20220413,
    amount: 1385.3,
    category: categories.job,
    source: 'My employeer',
    destination: 'Debit account',
  },
  ...
]

etc...

As you can see, I have a categories there which means that I have in cycle every transaction in balances and I must create separate category for each of them with total amount for each category, count of items in category and with detailed transactions for each category. I'm using array.forEach() cycle:

balances.forEach((balance) => {

  // Checking if category already exists in my array of categories
  let categoryIndex = categories.findIndex((category) => category.category === balance.category)

  // Create details of transaction
  let transactionDetail = {
    date: balance.date,
    amount: balance.amount,
    source: balance.source,
    destination: balance.destination,
  }

  // If category already exists, just calculate total and add new object into array details
  if (categoryIndex !== -1) {
    console.log([categories[categoryIndex].details])
    categories[categoryIndex] = {
      type: balance.type,
      category: balance.category,
      amount: categories[categoryIndex].amount + balance.amount,
      count: (categories[categoryIndex].count += 1),

      // This row is wrong. I cannot use this
      details: [categories[categoryIndex].details].push(transactionDetail),
    }
  } else {
    // If category doesn't yet exists, we must create a first values in this category
    categories.push({
      type: balance.type,
      category: balance.category,
      amount: balance.amount,
      count: 1,
      details: [transactionDetail],
    })
  }
}

But the row

details: [categories[categoryIndex].details].push(transactionDetail)

doesn't work properly. Probably the reason is, that I have sometimes Object as tyopeof result and sometimes undefined

Row console.log([categories[categoryIndex].details]) sometimes output:

// Output for
// console.log([categories[categoryIndex].details])
[Array(1)]0: Array(1)
0: {date: 20220414, amount: 410, source: 'xxx', destination: 'yyy'}
length: 1[[Prototype]]: 
Array(0)length: 1
[[Prototype]]: Array(0)

[2]
0: 2
length: 1
[[Prototype]]: Array(0)

Any hiths how can add object transactionDetail as a next in existing array? Thank you very much for any advice.

I don't understand. I can concat string if category already exists, add numbers but I cannot add an next object into array of objects.

EDIT: Just changed transaction to trasactionDetail in explanation.


Solution

  • I found several errors in your latter block and have corrected them; let me explain the changes I've made.

    1. In the line you marked as wrong, you were putting brackets around the values for some reason. Categories.details is presumably an array of TransactionDetail, so you don't need to further nest it here. However, if you push into an array, that returns with the number of objects in the array, so when you did this in that line, details would ultimately always be populated with a number. Rather, in my version, I split out the existing category you pulled via index as existing and simply push the value to its details array. This also just cleans up the top half of your condition since one need only reference the properties from the existing object to match against the new values in a cleaner way.

    2. You were using 1(categories[categoryIndex].count += 1) to increase the count. But, you're also setting precisely that object here, so this isn't a good practice. Rather, set the values you intend to use here and commit it all to the categories array as one thing, instead of a mismatch of some values setting here, some set differently. I corrected this to a mere existing.count + 1.

    Here's your updated code in full then:

    balances.forEach((balance) => {
    
      // Checking if category already exists in my array of categories
      let categoryIndex = categories.findIndex(category => category.category === balance.category);
    
      // Create details of transaction
      let transactionDetail = {
        date: balance.date,
        amount: balance.amount,
        source: balance.source,
        destination: balance.destination,
      };
    
      // If category already exists, just calculate total and add new object into array details
      if (categoryIndex !== -1) {
        const existing = categories[categoryIndex];
        existing.details.push(transactionDetail);
    
        categories[categoryIndex] = {
          type: balance.type,
          category: balance.category,
          amount: existing.amount + balance.amount,
          count: existing.count + 1,
          details: existing.details
        };
      } else {
        // If category doesn't yet exists, we must create a first values in this category
        categories.push({
          type: balance.type,
          category: balance.category,
          amount: balance.amount,
          count: 1,
          details: [transactionDetail],
        });
      }
    });