I’m trying to do this: I have an array of objects with the detail of a sale, with this format:
[
{
product:Banana,
quantity:34,
...(other fields)
},
{
product:Apple,
quantity:11,
...(other fields)
},
{
product:Banana,
quantity:15,
...(other fields)
},
{
product:Apple,
quantity:9,
...(other fields)
},
{
product:Orange,
quantity:7,
...(other fields)
}
]
From that array, I’d like to create a new one, with just one field by each product existing in the original array, and the total quantity of every product on the detail, like this:
[
{
product:Banana,
quantity:49 //(34 + 15) from the original array
},
{
product:Apple,
quantity:20 //(11 + 9) from the original array
},
{
product:Orange,
quantity:7 //Just 7 from the original array
}
]
Currently, I have this code which actually works (the variable names are in spanish):
const validarDetalle = async function (detalle) {
//'detalle' is the original array received by parameter
let error=false;
let arrayProductosCantidades=[]; //This is the new array which I'm generating
//I iterate on the original array with a for
for (const elemDetalle of detalle) {
console.log(elemDetalle);
//When the new array it's initially empty, I just concatenate
//the first product and quantity found on the original array to it
if(arrayProductosCantidades.length==0) {
arrayProductosCantidades=arrayProductosCantidades.concat(
{
producto:elemDetalle.producto,
cantidad:Number(elemDetalle.cantidad)
});
}
//If it isn't empty, I look if the product of the element
//of the original array
//where I'm standing already exists on the new array
else if(
(!arrayProductosCantidades.some (
function(productoCantidad) {
return (productoCantidad.producto == elemDetalle.producto)
}
)
)
)
{
//If it doesn't exists, I concatenate an element to the new array
//with the product and quantity of that element of the original array
arrayProductosCantidades=arrayProductosCantidades.concat(
{
producto:elemDetalle.producto,
cantidad:Number(elemDetalle.cantidad)
}
);
}
//If the product already exists on the new array,
//I create a variable 'elementoProductoCantidad' with the
//previous value of that element in the new array
else{
let elementoProductoCantidad=
arrayProductosCantidades.find (
function(productoCantidad) {
return(productoCantidad.producto == elemDetalle.producto)
}
);
//In that variable, I update the quantity field, adding to it the quantity
//of the element of the original array in where I'm standing
elementoProductoCantidad.cantidad += Number(elemDetalle.cantidad);
//After that, I delete the element of the new array with the old quantity value
arrayProductosCantidades=arrayProductosCantidades.filter(prodCant => prodCant.producto!=elemDetalle.producto);
//Finally I concatenate it again, with the quantity value updated
arrayProductosCantidades=arrayProductosCantidades.concat(elementoProductoCantidad);
}
}
console.log(arrayProductosCantidades);
//Once I've generated the new array, I make a validation for every product existing in my database
//(I should never get a negative stock in any product sold)
for (const elemProdCant of arrayProductosCantidades) {
const producto = await Number(elemProdCant.producto);
const cantidad = await Number(elemProdCant.cantidad);
let productoActualizado= await Producto.findById(elemProdCant.producto);
if(Number(productoActualizado.stock) - Number(cantidad) < 0) {
error=true;
}
}
return error;
}
Althrough this works fine, I think it should be a better way to do this in a functional way, using functions like map and reduce instead of for loops.
Does anyone have an idea if this it’s possible and/or convenient?
Thank’s a lot!
2
Answers
One easy way would be to first build a
quantityByProduct
object (lookup table) that contains the total quantity for each product and then use that to construct the final array of objects.The above code utilizes functional methods to consolidate liked objects