How to update many nested arrays within the same document

I recently started learning about the MERN stack, and in a project, I’m trying to add attendance records for every student from the same class.
My schema looks like this :slight_smile:

const classesSchema = new Schema(
    {
        name:{type: String, required: true},
        students: [{
            // other fields go here
            attendance:[{
                date:{type: Date},
                tHours:{type: Number},
                aHours:{type: Number}
            }],
        }]
    }, 
    {
        timestamps: true
    }
)

To make it clear, imagine there are two students in the “students” array, I want for example to add every item from this array [{date: “2023-08-11”, tHours: 2, aHours; 1}, { “2023-08-11”, tHours: 2, aHours; 0}] to the student which has the same index.

I tried something like this but it didn’t work :

app.post("/api/classes/:id/students/attendance", async(req, res) => {
    try {
        req.body.forEach((element, index) => {
            const attendanceObj = {
                date: element.date,
                tHours: element.tHours,
                aHours: element.aHours
            }
            classModel.updateOne(
                {_id: req.params.id}, 
                { $push: { "students.attendance": attendanceObj } }
            );
            res.json("A new attendance record has been added successfully!");
            
        });
    } catch (error) {
        res.status(500).json({ error: "An error occured while adding a record!"});
    }
});

I don’t know exactly what is your expectation about this request but you are calling
res.json() inside a foreach. In this case your foreach just will run the first element and make a response to request according express docs.

Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string using JSON.stringify().
The parameter can be any JSON type, including object, array, string, Boolean, number, or null, and you can also use it to convert other values to JSON.

Maybe just make your foreach sync operation using await before updateOne and on forEach and making the response only after the foreach do all updates successfully you finally can make a response.

Sometihing like:

try {
        for (const element of req.body ) {
            const attendanceObj = {
                date: element.date,
                tHours: element.tHours,
                aHours: element.aHours
            }
            await classModel.updateOne(
                {_id: req.params.id}, 
                { $push: { "students.attendance": attendanceObj } }
            );

            
        });
            res.json("A new attendance record has been added successfully!");
    } catch (error) {
        res.status(500).json({ error: "An error occured while adding a record!"});
    }
});
1 Like

Thank you for replying
Yeah, I tried this way before but I don’t know why it didn’t work.
On the other hand, this one worked for me :

app.post("/api/classes/:name/students/attendance", async(req, res) => {
    try {
        const data = await classModel.findOne({ name: req.params.name })
        data.students.forEach((student) => {
            student.attendance.push({date: req.body.date, tHours: req.body.tHours, aHours: req.body[`${student._id}`]})
        })
        await data.save()
        res.json("A new attendance record has been added successfully!");
    } catch (error) {
        res.status(500).json({ error: "An error occured while adding an attendance record!"});
    }
});