How to call reduce over empty array and assign new properties

I have an object with default properties and two arrays, where one of these is empty. The empty array has the possibility to not be empty on some occasions, but I still want to loop over it. If the array is empty, reduce won't be called and I will be missing some properties, so the idea is to have some default properties in the object in case the array is empty. The expected result is something like this:

[{
  "playedOffTickets": 60,
  "playedOffRevenue": 1730.5,
  "Transactions.deliveryMethod": "Print At Home Delivery",
  "soldTickets": 0,
  "soldRevenue": 0,
 },
 {
  "playedOffTickets": 43,
  "playedOffRevenue": 1160,
  "Transactions.deliveryMethod": "Postal Delivery",
  "soldTickets": 0,
  "soldRevenue": 0,
 },
 {
  "playedOffTickets": 12,
  "playedOffRevenue": 348,
  "Transactions.deliveryMethod": "Cobo Delivery",
  "soldTickets": 0,
  "soldRevenue": 0,
 },
 {
  "playedOffTickets": -3,
  "playedOffRevenue": -87,
  "Transactions.deliveryMethod": "",
  "soldTickets": 0,
  "soldRevenue": 0,
}];

But the response I'm getting is not what I want. What am I doing wrong? Thanks in advance!

const productMap = {
      soldTickets: 0,
      soldRevenue: 0,
      playedOffTickets: 0,
      playedOffRevenue: 0,
    };

    const arr1 = [];
    const arr2 = [
      {
         "Transactions.deliveryMethod": "Print At Home Delivery",
         "Transactions.itemCount": "60",
         "Transactions.revenue": "1730.5"
      },
      {
         "Transactions.deliveryMethod": "Postal Delivery",
         "Transactions.itemCount": "43",
         "Transactions.revenue": "1160"
      },
      {
         "Transactions.deliveryMethod": "Cobo Delivery",
         "Transactions.itemCount": "12",
         "Transactions.revenue": "348"
      },
      {
         "Transactions.deliveryMethod": "",
         "Transactions.itemCount": "-3",
         "Transactions.revenue": "-87"
      }
    ];

    arr1.reduce((p, salesData) => {
      const product = salesData["Transactions.deliveryMethod"];
      p[product] = p[product] || {};
      const soldTickets = Number(salesData["Transactions.itemCount"]);
      const soldRevenue = Number(salesData["Transactions.revenue"]);

      p[product].soldTickets = p[product].soldTickets || 0;
      p[product].soldTickets += soldTickets;

      p[product].soldRevenue = p[product].soldRevenue || 0;
      p[product].soldRevenue += soldRevenue;

      p[product]["Transactions.deliveryMethod"] = product;

      return p;
    }, productMap);

    arr2.reduce((p, playedOffData) => {
      const product = playedOffData["Transactions.deliveryMethod"];
      p[product] = p[product] || {};
      const playedOffTickets = Number(playedOffData["Transactions.itemCount"]);
      const playedOffRevenue = Number(playedOffData["Transactions.revenue"]);

      p[product].playedOffTickets = p[product].playedOffTickets || 0;
      p[product].playedOffTickets += playedOffTickets;

      p[product].playedOffRevenue = p[product].playedOffRevenue || 0;
      p[product].playedOffRevenue += playedOffRevenue;

      p[product]["Transactions.deliveryMethod"] = product;

      return p;
    }, productMap);

    const productMapData = Object.values(productMap);
    
    console.log(productMapData)

Solution 1:

I would suggest adding a productMapDefaults object, we'd use this whenever we want to create a new entry in the productMap object.

One can then customize as necessary to add new properties.

const productMap = {};

const productMapDefaults = { 
    soldTickets: 0,
    soldRevenue: 0,
    playedOffTickets: 0,
    playedOffRevenue: 0
}

const arr1 = [];
const arr2 = [
  {
     "Transactions.deliveryMethod": "Print At Home Delivery",
     "Transactions.itemCount": "60",
     "Transactions.revenue": "1730.5"
  },
  {
     "Transactions.deliveryMethod": "Postal Delivery",
     "Transactions.itemCount": "43",
     "Transactions.revenue": "1160"
  },
  {
     "Transactions.deliveryMethod": "Cobo Delivery",
     "Transactions.itemCount": "12",
     "Transactions.revenue": "348"
  },
  {
     "Transactions.deliveryMethod": "",
     "Transactions.itemCount": "-3",
     "Transactions.revenue": "-87"
  }
];

arr1.reduce((p, salesData) => {
  const product = salesData["Transactions.deliveryMethod"];
  // Use productMapDefaults as template when creating new entry...
  p[product] = p[product] || { ...productMapDefaults };
  const soldTickets = Number(salesData["Transactions.itemCount"]);
  const soldRevenue = Number(salesData["Transactions.revenue"]);

  p[product].soldTickets = p[product].soldTickets || 0;
  p[product].soldTickets += soldTickets;

  p[product].soldRevenue = p[product].soldRevenue || 0;
  p[product].soldRevenue += soldRevenue;

  p[product]["Transactions.deliveryMethod"] = product;

  return p;
}, productMap);

arr2.reduce((p, playedOffData) => {
  const product = playedOffData["Transactions.deliveryMethod"];
  // Use productMapDefaults as template when creating new entry...
  p[product] = p[product] || { ...productMapDefaults };
  const playedOffTickets = Number(playedOffData["Transactions.itemCount"]);
  const playedOffRevenue = Number(playedOffData["Transactions.revenue"]);

  p[product].playedOffTickets = p[product].playedOffTickets || 0;
  p[product].playedOffTickets += playedOffTickets;

  p[product].playedOffRevenue = p[product].playedOffRevenue || 0;
  p[product].playedOffRevenue += playedOffRevenue;

  p[product]["Transactions.deliveryMethod"] = product;

  return p;
}, productMap);

const productMapData = Object.values(productMap);
console.log(productMapData)
    
.as-console-wrapper { max-height: 100% !important; top: 0; }