Aquí está el escenario que estoy viendo:
Quiero reducir estos objetos
const data = [ { id: 1, totalAmount: 1500, date: '2021-01-01', vendor_id: 2, totalTransaction: 12, isRefund: false, }, { id: 2, totalAmount: 200, date: '2021-01-01', vendor_id: 2, totalTransaction: 2, isRefund: true, }, { id: 3, totalAmount: 200, date: '2021-01-01', vendor_id: 2, totalTransaction: 1, isRefund: true, }, ];y encontré una solución que suma sus valores:
const deepMergeSum = (obj1, obj2) => { return Object.keys(obj1).reduce((acc, key) => { if (typeof obj2[key] === 'object') { acc[key] = deepMergeSum(obj1[key], obj2[key]); } else if (obj2.hasOwnProperty(key) && !isNaN(parseFloat(obj2[key]))) { acc[key] = obj1[key] + obj2[key] } return acc; }, {}); }; const result = data.reduce((acc, obj) => (acc = deepMergeSum(acc, obj))); const array = [] const newArray = [...array, result]lo que resulta en:
const newArray = [ { id: 6, totalAmount: 1900, date: '2021-01-012021-01-012021-01-01', vendor_id: 6, totalTransaction: 15 } ] Y ahora mi problema es que todavía no sé cómo resolver esto para obtener el resultado esperado, que si isRefund es verdadero, debe restarse en lugar de agregarse, conservar el vendor_id y también la date concatenada en lugar de una sola fecha de entrada :
const newArray = [ { id: 1(generate new id if possible), totalAmount: 1100, date: '2021-01-01', vendor_id: 2, totalTransaction: 15, isRefund: null(this can be removed if not applicable), }, ];Aceptaré y trataré de entender cualquier forma mejor o solución para esto. Muchísimas gracias.
Como desea un comportamiento personalizado para varios campos y no necesita el aspecto recursivo de la combinación, le sugiero que cree una función de combinación personalizada, específica para su lógica comercial:
const data = [{id: 1,totalAmount: 1500,date: '2021-01-01',vendor_id: 2,totalTransaction: 12,isRefund: false,},{id: 2,totalAmount: 200,date: '2021-01-01',vendor_id: 2,totalTransaction: 2,isRefund: true,},{id: 3,totalAmount: 200,date: '2021-01-01',vendor_id: 2,totalTransaction: 1,isRefund: true,},]; function customMerge(a, b) { if (a.vendor_id !== b.vendor_id || a.date !== b.date) { throw "Both date and vendor_id must be the same"; } return { id: Math.max(a.id, b.id), totalAmount: (a.isRefund ? -a.totalAmount : a.totalAmount) + (b.isRefund ? -b.totalAmount : b.totalAmount), date: a.date, vendor_id: a.vendor_id, totalTransaction: a.totalTransaction + b.totalTransaction }; } const result = data.reduce(customMerge); if (data.length > 1) result.id++; // Make id unique console.log(result); También puede volver a introducir la propiedad isRefund en el resultado para cuando el monto total resulte ser negativo (solo haga esto cuando data.length > 1 ya que, de lo contrario, el result es solo el único objeto original en data ):
result.isRefund = result.totalAmount < 0; result.totalAmount = Math.abs(result.totalAmount); A continuación, utilice un "diccionario" (objeto simple o Map ) con claves por combinaciones de fecha/proveedor, cada una con un objeto de agregación como valor.
Para demostrarlo, agregué un objeto más en los datos que tiene una fecha diferente y una cantidad de 300:
const data = [{id: 1,totalAmount: 1500,date: '2021-01-01',vendor_id: 2,totalTransaction: 12,isRefund: false,},{id: 2,totalAmount: 200,date: '2021-01-01',vendor_id: 2,totalTransaction: 2,isRefund: true,},{id: 3,totalAmount: 200,date: '2021-01-01',vendor_id: 2,totalTransaction: 1,isRefund: true,},{id: 4,totalAmount: 300,date: '2021-01-02',vendor_id: 2,totalTransaction: 1,isRefund: false,}]; function customMerge(acc, {id, date, vendor_id, totalAmount, totalTransaction, isRefund}) { let key = date + "_" + vendor_id; if (!(id <= acc.id)) acc.id = id; acc[key] ??= { date, vendor_id, totalAmount: 0, totalTransaction: 0 }; acc[key].totalAmount += isRefund ? -totalAmount : totalAmount; acc[key].totalTransaction += totalTransaction; return acc; } let {id, ...grouped} = data.reduce(customMerge, {}); let result = Object.values(grouped).map(item => Object.assign(item, { id: ++id })); console.log(result);podría ser de ayuda, si está buscando el mismo resultado, puede agregar otra lista de verificación según sus requisitos, para la fecha filtrada, la lógica sería un poco diferente pero el resultado será el mismo.
const getTotalTranscation = () => transctionLists.reduce((prev, current) => { const totalAmount = current.isRefund ? prev.totalAmount - current.totalAmount : prev.totalAmount + current.totalAmount; const totalTransaction = current.isRefund ? prev.totalTransaction - current.totalTransaction : prev.totalTransaction + current.totalTransaction; return { ...current, id: current.id + 1, totalAmount, totalTransaction, isRefund: totalAmount < 0, }; });