Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

122
Views
How to combine all objects into one based on key

Here is the scenario I am looking at:

I want to reduce these objects

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,
  },
];

and I found a solution that adds their values:

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]

which results to:

const newArray = [
 {
   id: 6,
   totalAmount: 1900,
   date: '2021-01-012021-01-012021-01-01',
   vendor_id: 6,
   totalTransaction: 15
 }
]

And now my problem is I don't know yet how to work this around to have my expected output which if isRefund is true, it must be subtracted instead of being added, retain the vendor_id and also the concatenated date instead of only one entry date:

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),
 },
];

I will accept and try to understand any better way or workaround for this. Thank you very much.

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

As you want custom behaviour for several fields, and don't need the recursive aspect of the merge, I would suggest you create a custom merge function, specific to your business logic:

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);

You could also reintroduce the isRefund property in the result for when the total amount turns out to be negative (only do this when data.length > 1 as otherwise result is just the original single object in data):

result.isRefund = result.totalAmount < 0;
result.totalAmount = Math.abs(result.totalAmount);

Distinct results for different dates and/or vendors

Then use a "dictionary" (plain object or Map) keyed by date/vendor combinations, each having an aggregating object as value.

To demonstrate, I added one more object in the data that has a different date and amount of 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);

about 4 years ago · Juan Pablo Isaza Report

0

it could be help, if you are looking for the same output, can add other checklist based on your requirement, for filtered date, logic would be little different but the output will be same.

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,
    };
  });
about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!