Error while using concat to flatten an array

Issue

Here’s the issue:
I’m trying to flatten an array of sales, in which every element has an id, a sale code, a seller username associated, a timestamp, and a detail. The detail consist of an array with a product, an amount, and a subtotal for every item in each one.
For example, the complete sales array looks like this:

[
    {
    "_id":"63182596a51be828aa351daf",
    "codVenta":1,
    "vendedor":"rosittog",
    "detalle":
        [
            {
                "producto":"3",
                "cantidad":1,
                "tipoPago":"efectivo",
                "subtotal":23,
                "_id":"63182596a51be828aa351db0"
                },
            {
                "producto":"4",
                "cantidad":1,
                "tipoPago":"efectivo",
                "subtotal":55,
                "_id":"63182596a51be828aa351db1"
                }
        ],
    "fechaHora":"2022-09-07T05:01:10.462Z",
    "__v":0
    },

    {
        "_id":"631845c706b2c211ed6f5ca9",
        "codVenta":1,
        "vendedor":"rosittog",
        "detalle":
        [
            {
                "producto":"4",
                "cantidad":1,
                "tipoPago":"efectivo",
                "subtotal":55,
                "_id":"631845c706b2c211ed6f5caa"
                }
        ],
        "fechaHora":"2022-09-07T07:18:30.829Z",
        "__v":0
    }
]

What I’m trying to do is flattening the array, so I can have something like this:

[
    {   
        "_id":"63182596a51be828aa351db0",
        "idVentaAsociada":"63182596a51be828aa351daf",
        "codVenta":1,
        "vendedor":"rosittog",
        "producto":"3",
        "cantidad":1,
        "tipoPago":"efectivo",
        "subtotal":23,
        "fechaHora":"2022-09-07T05:01:10.462Z"
    },
    
    {
        "_id":"63182596a51be828aa351db1",
        "idVentaAsociada":"63182596a51be828aa351daf",
        "codVenta":1,
        "vendedor":"rosittog",
        "producto":"4",
        "cantidad":1,
        "tipoPago":"efectivo",
        "subtotal":55,
        "fechaHora":"2022-09-07T05:01:10.462Z"
    },
    
    {
        "_id":"631845c706b2c211ed6f5caa",
        "idVentaAsociada":"631845c706b2c211ed6f5ca9",
        "codVenta":1,
        "vendedor":"rosittog",
        "producto":"4",
        "cantidad":1,
        "tipoPago":"efectivo",
        "subtotal":55,
        "fechaHora":"2022-09-07T05:01:10.462Z"
    }
]

This is: I need an element of the flattened array for every detail in every sale. For example, in the original array we had a sale with two items on the detail ("detalle" in spanish), and another one with just one item. So then, the flattened array should have three items total.

What I’m trying to do for that purpose, is this:

const aplanarVentas=function (ventas) {
    let arrayVentasPlano=[];

    //ventas.map(function (venta){
    for (const venta of ventas) {

        let ventaPlana= {
            _id:'',
            idVentaAsociada:'',
            codVenta:0,
            vendedor:'',
            producto:0,
            cantidad:0,
            tipoPago:'',
            subtotal:0
        };

        ventaPlana.idVentaAsociada=venta._id;
        ventaPlana.codVenta=venta.codVenta;
        ventaPlana.vendedor=venta.vendedor;
        ventaPlana.fechaHora=venta.fechaHora;

        //venta.detalle.map(function (elemDetalle){ 
        for (const elemDetalle of venta.detalle) {

            console.log("Entro al for");

            //console.log(elemDetalle);
            ventaPlana._id=elemDetalle._id;
            ventaPlana.producto=elemDetalle.producto;
            ventaPlana.cantidad=elemDetalle.cantidad;
            ventaPlana.tipoPago=elemDetalle.tipoPago;
            ventaPlana.subtotal=elemDetalle.subtotal


            
            console.log("Before updating arrayVentasPlano");
            console.log(arrayVentasPlano);


            /*Validation tried
                        if (!arrayVentasPlano.some(
                            function (venta) {
                                return venta._id==elemDetalle._id
                                }
                            )
                            )
                        {
            */
            arrayVentasPlano=arrayVentasPlano.concat(ventaPlana);
            //arrayVentasPlano.push(ventaPlana);
            
            console.log("After updating arrayVentasPlano");
            console.log(arrayVentasPlano);
            //}

        }
        //}) 
        //console.log(arrayVentasPlano);
        return arrayVentasPlano;
    }
    //})
}

I’ve left some lines I tried before as comments: using map instead of for, using push instead of concat, and also the "some" function for validation, but none of that stuff worked.

The response I have is this one (special attention to _id fields):

[
    {   
        "_id":"63182596a51be828aa351db1",
        "idVentaAsociada":"63182596a51be828aa351daf",
        "codVenta":1,
        "vendedor":"rosittog",
        "producto":"4",
        "cantidad":1,
        "tipoPago":"efectivo",
        "subtotal":55,
        "fechaHora":"2022-09-07T05:01:10.462Z"
    },
    
    {
        "_id":"63182596a51be828aa351db1",
        "idVentaAsociada":"63182596a51be828aa351daf",
        "codVenta":1,"vendedor":"rosittog",
        "producto":"4",
        "cantidad":1,
        "tipoPago":"efectivo",
        "subtotal":55,
        "fechaHora":"2022-09-07T05:01:10.462Z"
    }
]

Just only an array of two elements, with fields corresponding to detail duplicated

My ouput in the console is this one:

Entro al for
Before updating arrayVentasPlano
[]
After updating arrayVentasPlano
[
  {
    _id: new ObjectId("63182596a51be828aa351db0"),
    idVentaAsociada: new ObjectId("63182596a51be828aa351daf"),
    codVenta: 1,
    vendedor: 'rosittog',
    producto: '3',
    cantidad: 1,
    tipoPago: 'efectivo',
    subtotal: 23,
    fechaHora: 2022-09-07T05:01:10.462Z
  }
]
Entro al for
Before updating arrayVentasPlano
[
  {
    _id: new ObjectId("63182596a51be828aa351db1"),
    idVentaAsociada: new ObjectId("63182596a51be828aa351daf"),
    codVenta: 1,
    vendedor: 'rosittog',
    producto: '4',
    cantidad: 1,
    tipoPago: 'efectivo',
    subtotal: 55,
    fechaHora: 2022-09-07T05:01:10.462Z
  }
]
After updating arrayVentasPlano
[
  {
    _id: new ObjectId("63182596a51be828aa351db1"),
    idVentaAsociada: new ObjectId("63182596a51be828aa351daf"),
    codVenta: 1,
    vendedor: 'rosittog',
    producto: '4',
    cantidad: 1,
    tipoPago: 'efectivo',
    subtotal: 55,
    fechaHora: 2022-09-07T05:01:10.462Z
  },
  {
    _id: new ObjectId("63182596a51be828aa351db1"),
    idVentaAsociada: new ObjectId("63182596a51be828aa351daf"),
    codVenta: 1,
    vendedor: 'rosittog',
    producto: '4',
    cantidad: 1,
    tipoPago: 'efectivo',
    subtotal: 55,
    fechaHora: 2022-09-07T05:01:10.462Z
  }
]

As you can see: in the first iteration, it appends the item correctly to the arrayPlanoVentas ("plano" means flat, "ventas" means sales), but in the next iteration I don’t have the element previously appended.

What I’m doing wrong? I’ve tried almost everything.

If it’s needed, here’s the function from where I call aplanarVentas (I’m using express and mongoose):

router.route('/asociarAplanar').get( async(req, res) => {
    
    try {
        const ventas=await Venta.find();
        //Por cada venta, necesito N elementos
        const ventasAplanadas= await aplanarVentas(ventas);

        
        const usuarios= await Usuario.find({categoria: "vendedor"});
        const productos= await Producto.find();
        const cuentas= await Cuentas.findById("unico");
        return res.json({
            "ventas":ventasAplanadas,
            "usuarios":usuarios,
            "productos":productos,
            "cuentas":cuentas
        });
    }
    catch(err) {
        console.log(err);
        return res.status(400).json('Error: ' + err);
    }

})

Solution

Make the following two changes to fix your code:

  1. Array#concat a copy of ventaPlana instead of ventaPlana by changing:

    arrayVentasPlano=arrayVentasPlano.concat(ventaPlana);
    

to:

    arrayVentasPlano=arrayVentasPlano.concat({...ventaPlana});
  1. Move return arrayVentasPlano; so that it is outside the outer for loop

DEMO

const v = [
    {
    "_id":"63182596a51be828aa351daf",
    "codVenta":1,
    "vendedor":"rosittog",
    "detalle":
        [
            {
                "producto":"3",
                "cantidad":1,
                "tipoPago":"efectivo",
                "subtotal":23,
                "_id":"63182596a51be828aa351db0"
                },
            {
                "producto":"4",
                "cantidad":1,
                "tipoPago":"efectivo",
                "subtotal":55,
                "_id":"63182596a51be828aa351db1"
                }
        ],
    "fechaHora":"2022-09-07T05:01:10.462Z",
    "__v":0
    },

    {
        "_id":"631845c706b2c211ed6f5ca9",
        "codVenta":1,
        "vendedor":"rosittog",
        "detalle":
        [
            {
                "producto":"4",
                "cantidad":1,
                "tipoPago":"efectivo",
                "subtotal":55,
                "_id":"631845c706b2c211ed6f5caa"
                }
        ],
        "fechaHora":"2022-09-07T07:18:30.829Z",
        "__v":0
    }
];

const aplanarVentas=function (ventas) {
    let arrayVentasPlano=[];

    for (const venta of ventas) {

        let ventaPlana= {
            _id:'',
            idVentaAsociada:'',
            codVenta:0,
            vendedor:'',
            producto:0,
            cantidad:0,
            tipoPago:'',
            subtotal:0
        };

        ventaPlana.idVentaAsociada=venta._id;
        ventaPlana.codVenta=venta.codVenta;
        ventaPlana.vendedor=venta.vendedor;
        ventaPlana.fechaHora=venta.fechaHora;

        for (const elemDetalle of venta.detalle) {
            ventaPlana._id=elemDetalle._id;
            ventaPlana.producto=elemDetalle.producto;
            ventaPlana.cantidad=elemDetalle.cantidad;
            ventaPlana.tipoPago=elemDetalle.tipoPago;
            ventaPlana.subtotal=elemDetalle.subtotal
            arrayVentasPlano=arrayVentasPlano.concat({...ventaPlana});
        }
    }
    return arrayVentasPlano;
}

console.log( aplanarVentas( v ) );

Answered By – PeterKA

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published