Reputation: 1391
I have this code:
let result = Object.values(response.data.reduce((r,{ PO_NO, PO_LINE_NO, MATERIAL_NO, MATERIAL_NAME, PO_QTY, GRPO_QTY, GRPO_SHIPDATE }) => {
r[PO_NO] = r[PO_NO] || { PO_NO, LINES: [] }
r[PO_NO].LINES.push({
LINE_NO: PO_LINE_NO,
PO_QTY: PO_QTY,
MATERIAL_NO: MATERIAL_NO,
MATERIAL_NAME: MATERIAL_NAME,
GRPO_QTY: GRPO_QTY,
GRPO_SHIPDATE: GRPO_SHIPDATE
})
return r
},{}))
Which results into an array of nested objects. However, in the LINES.push() part, there are items that have the same line_no, material_no, material_name, and po_qty. The difference are grpo_qty and grpo_shipdate.
Is it possible to do remove the shipdate and get the sum of grpo_qty with the same line_no for every po_no so that I only have a single row per line_no of every po_no?
Example of response.data content:
{
"PO_NO": 35159,
"LINES": [
{
"LINE_NO": 15,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 160000,
"GRPO_SHIPDATE": "September, 21 2017 00:00:00"
},
{
"LINE_NO": 15,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 320800,
"GRPO_SHIPDATE": "October, 07 2017 00:00:00"
},
{
"LINE_NO": 15,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 19200,
"GRPO_SHIPDATE": "October, 20 2017 00:00:00"
},
{
"LINE_NO": 16,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 60000,
"GRPO_SHIPDATE": "September, 13 2017 00:00:00"
},
{
"LINE_NO": 16,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 440000,
"GRPO_SHIPDATE": "October, 20 2017 00:00:00"
}
]
},
Upvotes: 0
Views: 52
Reputation: 23999
I would iterate over the array and sum the quantities:
const newLines = [],
lineNumbers = [];
lines.forEach(line => {
delete line.GRPO_SHIPDATE; /* delete shipdate */
if (!lineNumbers.includes(line.LINE_NO)) {
lineNumbers.push(line.LINE_NO); /* store current LINE_NO */
newLines.push(line);
} else {
let toChange = newLines.filter(ln => { /* get current LINE_NO */
return ln.LINE_NO === line.LINE_NO
});
toChange[0].GRPO_QTY = toChange[0].GRPO_QTY + line.GRPO_QTY;
}
});
const lines = [{
"LINE_NO": 15,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 160000,
"GRPO_SHIPDATE": "September, 21 2017 00:00:00"
},
{
"LINE_NO": 15,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 320800,
"GRPO_SHIPDATE": "October, 07 2017 00:00:00"
},
{
"LINE_NO": 15,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 19200,
"GRPO_SHIPDATE": "October, 20 2017 00:00:00"
},
{
"LINE_NO": 16,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 60000,
"GRPO_SHIPDATE": "September, 13 2017 00:00:00"
},
{
"LINE_NO": 16,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 440000,
"GRPO_SHIPDATE": "October, 20 2017 00:00:00"
}
]
const newLines = [],
lineNumbers = [];
lines.forEach(line => {
delete line.GRPO_SHIPDATE; /* delete shipdate */
if (!lineNumbers.includes(line.LINE_NO)) {
lineNumbers.push(line.LINE_NO); /* store current LINE_NO */
newLines.push(line);
} else {
let toChange = newLines.filter(ln => { /* get current LINE_NO */
return ln.LINE_NO === line.LINE_NO
});
toChange[0].GRPO_QTY = toChange[0].GRPO_QTY + line.GRPO_QTY;
}
});
console.log(newLines)
Upvotes: 0
Reputation: 135367
Writing functions matchLine
and combineLine
help us break groupPoLines
down into an easier task - note, each function here will NOT mutate its inputs
const matchLine = (a, b) =>
a.LINE_NO === b.LINE_NO
&& a.PO_QTY === b.PO_QTY
&& a.MATERIAL_NO === b.MATERIAL_NO
const combineLine = ({ GRPO_SHIPDATE:_, ...a }, b) =>
({ ...a, GRPO_QTY: a.GRPO_QTY + b.GRPO_QTY })
const groupPoLines = ({ LINES, ...po }) => ({
...po,
LINES: LINES.reduce ((r, x) => {
const i = r.findIndex (y => matchLine (x, y))
if (i < 0)
return [ ...r, x ]
else
return Object.assign (r, { [i]: combineLine (r[i], x) })
}, [])
})
console.log (groupPoLines (data))
// { PO_NO: 35159,
// LINES:
// [ { LINE_NO: 15,
// PO_QTY: 500000,
// MATERIAL_NO: '130227',
// MATERIAL_NAME: 'T3-0381 Base Mold φ10 M2',
// GRPO_QTY: 500000 },
// { LINE_NO: 16,
// PO_QTY: 500000,
// MATERIAL_NO: '130227',
// MATERIAL_NAME: 'T3-0381 Base Mold φ10 M2',
// GRPO_QTY: 500000 } ] }
If you have an array of POs, you can simply map
our new function over it
console.log (poList.map (po => groupPoLines (po)))
// [ { PO_NO: 1, LINES: [ ... ] }, { PO_NO: 2, LINES: [ ... ] } ]
Expand the snippet to verify it works
const data = {
"PO_NO": 35159,
"LINES": [
{
"LINE_NO": 15,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 160000,
"GRPO_SHIPDATE": "September, 21 2017 00:00:00"
},
{
"LINE_NO": 15,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 320800,
"GRPO_SHIPDATE": "October, 07 2017 00:00:00"
},
{
"LINE_NO": 15,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 19200,
"GRPO_SHIPDATE": "October, 20 2017 00:00:00"
},
{
"LINE_NO": 16,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 60000,
"GRPO_SHIPDATE": "September, 13 2017 00:00:00"
},
{
"LINE_NO": 16,
"PO_QTY": 500000,
"MATERIAL_NO": "130227",
"MATERIAL_NAME": "T3-0381 Base Mold φ10 M2",
"GRPO_QTY": 440000,
"GRPO_SHIPDATE": "October, 20 2017 00:00:00"
}
]
}
const matchLine = (a, b) =>
a.LINE_NO === b.LINE_NO
&& a.PO_QTY === b.PO_QTY
&& a.MATERIAL_NO === b.MATERIAL_NO
const combineLine = ({ GRPO_SHIPDATE:_, ...a }, b) =>
({ ...a, GRPO_QTY: a.GRPO_QTY + b.GRPO_QTY })
const groupPoLines = ({ LINES, ...po }) => ({
...po,
LINES: LINES.reduce ((r, x) => {
const i = r.findIndex (y => matchLine (x, y))
if (i < 0)
return [ ...r, x ]
else
return Object.assign (r, { [i]: combineLine (r[i], x)})
}, [])
})
console.log (groupPoLines (data))
console.log ('---')
console.log ([data, data, data].map(d => groupPoLines (d)))
Upvotes: 1
Reputation: 3253
Well I think you can just iterate over each entry and call a reduce function on the lines array. In this function you can create a unique key with properties that stay the same and then sum up the grpo_qty values.
It could look something like this
result.forEach(entry => {
entry.LINES = Object.values(entry.LINES.reduce((result, current) => {
const uniqueKey = `${current.LINE_NO}-${current.MATERIAL_NO}-${current.PO_QTY}-${current.MATERIAL_NAME}`;
if (!result[uniqueKey]) {
result[uniqueKey] = {
LINE_NO: current.LINE_NO,
PO_QTY: current.PO_QTY,
MATERIAL_NO: current.MATERIAL_NO,
MATERIAL_NAME: current.MATERIAL_NAME,
GRPO_QTY: 0,
};
}
result[uniqueKey].GRPO_QTY += current.GRPO_QTY;
return result;
}, {}));
});
Maybe you can provide a jsfiddle so it is easier to test.
You could also imagine to do this in your original reduce. Creating the unique key there and also sum up the values. Then you later just need to convert the object back to an array.
Theoretically it would also be possible to directly write everything in an array and find the existing entry with array.find(), but personally I'd suggest using one of the reduce. It is a lot cleaner, more performant and easier to read
Upvotes: 0