Q: Modify values in an array of objects I have an array of objects and I would like to modify them based on a "type" value using another array of objects. I get a big list of objects but I am supposed to get only 2.
This is what I have:


const convertData = (type, value) => {
  switch (type) {
    case "date":
      {
        return new Date(Number(value)).toDateString();
      }
    case "currency":
      {
        return value ? `$${value}` : null;
      }
    default:
      return value;
  }
};

const headers = [{
  field: 'amount',
  type: 'currency'
}, {
  field: 'deliveredDate',
  type: 'date'
}]

const body = [{
  id: 1,
  amount: 4000,
  deliveredDate: "1610427600000"
}, {
  id: 2,
  amount: 6000,
  deliveredDate: "1611118800000"
}]

const result = body.map(i => {
  const keys = Object.keys(i);
  return keys.map(k => {
    return {
      ...i,
      [k]: headers.find(i => i.field === k) ? convertData(headers.find(i => i.field === k).type, i[k]) : null
    }
  })
})

console.log(result.flat())


/**
Expected Result
[{
  id: 1,
  amount: $4000,
  deliveredDate: "Tue Jan 12 2021"
}, {
  id: 2,
  amount: $6000,
  deliveredDate: "Wed Jan 20 2021"
}]
*/


The field value in headers represents the key in the body array. And the value in the corresponding body object needs to be changed as per the type in the header object. Please advise.

A: A possible approach, which also allows flexible adaption and code-reuse, takes advantage of the so often overlooked optional second argument, one is allowed to provide to most array methods ... thisArg for e.g. map.
Thus, such an approach does create a lookup table from the OP's headers list and does provide it to the mapping process since one does not want to search (within each iteration step of map) always again and again the same list in order to find the correct/matching related conversion type.
The actual mapping then will be easy. Implement a function which assumes its this context to be a lookup table and which does (re)create a type-converted version of the provided (here currently processed) object by looking up the correct conversion type before providing it to the OP's convertData function.


const convertData = (type, value) => {
  switch (type) {
    case "date": {
      return new Date(Number(value)).toDateString();
    }
    case "currency": {
      return value ? `$${value}` : null;
    }
    default:
      return value;
  }
};

const headers = [{
  field: 'amount',
  type: 'currency'
}, {
  field: 'deliveredDate',
  type: 'date'
}];

const body = [{
  id: 1,
  amount: 4000,
  deliveredDate: "1610427600000"
}, {
  id: 2,
  amount: 6000,
  deliveredDate: "1611118800000"
}];

function createConversionTypeLookupTable(conversionTypeList) {
  return conversionTypeList.reduce((table, conversionTypeItem) => {

    table[conversionTypeItem.field] = conversionTypeItem.type;
    return table;

  }, {});
}

function createConvertedItemViaBoundLookupTable(item) {
  const lookupTable = (this || {}); // more fail safe.
  return Object.entries(item).reduce((obj, [key, value]) => {

    obj[key] = convertData((lookupTable[key] || key), value);
    return obj;

  }, {});
}

console.log(
  'Converted Item List ...',
  body.map(
    createConvertedItemViaBoundLookupTable,
    createConversionTypeLookupTable(headers)
  )
);
console.log(
  'Conversion Type Lookup Table ...',
  createConversionTypeLookupTable(headers)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }



A: You are calling map twice, once on the array and again on the keys, hence you get more than the items in array, and the objects are not correct since you are calling convertData on different objects each time
Consider doing it as below -


const convertData = (type, value) => {
  switch (type) {
    case "date":
      {
        return new Date(Number(value)).toDateString();
      }
    case "currency":
      {
        return value ? `$${value}` : null;
      }
    default:
      return value;
  }
};

const headers = [{
  field: 'amount',
  type: 'currency'
}, {
  field: 'deliveredDate',
  type: 'date'
}]

const body = [{
  id: 1,
  amount: 4000,
  deliveredDate: "1610427600000"
}, {
  id: 2,
  amount: 6000,
  deliveredDate: "1611118800000"
}]

const result = body.map(i => {
  const newItem = {};
  for (const prop in i) {
    const header = headers.find(f => f.field === prop);
    const value = i[prop];
    newItem[prop] = header ? convertData(header.type, value) : value
  }
  return newItem;
});

console.log(result)



EDIT 1:


const convertData = (type, value) => {
  switch (type) {
    case "date":
      {
        return new Date(Number(value)).toDateString();
      }
    case "currency":
      {
        return value ? `$${value}` : null;
      }
    default:
      return value;
  }
};

const headers = [{
  field: 'amount',
  type: 'currency'
}, {
  field: 'deliveredDate',
  type: 'date'
}]

const body = [{
  id: 1,
  amount: 4000,
  deliveredDate: "1610427600000"
}, {
  id: 2,
  amount: 6000,
  deliveredDate: "1611118800000"
}]

const result = body.map(i => {
  const newItem = {};
  var keys = Object.keys(i);
  keys.forEach((prop) => {
    const header = headers.find(f => f.field === prop);
    const value = i[prop];
    newItem[prop] = header ? convertData(header.type, value) : value
  });
  return newItem;
});

console.log(result);




A: JSON.stringify() with a replacer function does what the OP is looking for.


// OP code and data
//
const convertData = (type, value) => {
  switch (type) {
    case "date":
      {
        return new Date(Number(value)).toDateString();
      }
    case "currency":
      {
        return value ? `$${value}` : null;
      }
    default:
      return value;
  }
};

const headers = [{
  field: 'amount',
  type: 'currency'
}, {
  field: 'deliveredDate',
  type: 'date'
}]

const body = [{
  id: 1,
  amount: 4000,
  deliveredDate: "1610427600000"
}, {
  id: 2,
  amount: 6000,
  deliveredDate: "1611118800000"
}]

// use the OP code to convert a value to a string formatted by its key
//
const convertField = (key, value) => {
  let header = headers.find(e => e.field === key)
  return header ? convertData(header.type, value) : value
}

const convertedStr = JSON.stringify(body, convertField);
const convertedObj = JSON.parse(convertedStr);
console.log(convertedObj);


