Home > database >  Update document in array of documents Mongoose
Update document in array of documents Mongoose

Time:09-05

I have 2 models: Book and Student. I would like to update a field of a specific book in the books array of the student model. How could I first query the student, query a book in the books array and after update the book object?

Book model:


const bookSchema = new mongoose.Schema({
    title:{
        type: String
    },
    length:{
        type:Number
    },
    author:{
        type:String
    },
    ISBN:{
        type:String
    },
    finished:{
        type:Boolean
    },
    dueDate:{
        type:String
    },
    imgURL:{
        type:String
    }
});

module.exports = mongoose.model("book", bookSchema);

Student model:

const mongoose = require('mongoose');
const bookSchema = require('./book').schema;

const studentSchema = new mongoose.Schema({
    name:{
        type: String,
        required: true
    },
    books:{
        type: [bookSchema]
    }
});

module.exports = mongoose.model("student", studentSchema);```

CodePudding user response:

You can use the $set operator inside the findOneAndUpdate method.

Let's say you have this student document with two books:

{
    "_id": "6314eda827c01a07746bceff",
    "name": "student 1",
    "books": [
        {
            "_id": "6314eda827c01a07746bcf00",
            "title": "book 1 title",
            "length": 1,
            "author": "book 1 author",
            "ISBN": "book 1 ISBN",
            "finished": true,
            "dueDate": "book 1 dueDate",
            "imgURL": "book 1 imgURL"
        },
        {
            "_id": "6314eda827c01a07746bcf01",
            "title": "book 2 title",
            "length": 2,
            "author": "book 2 author",
            "ISBN": "book 2 ISBN",
            "finished": false,
            "dueDate": "book 2 dueDate",
            "imgURL": "book 2 imgURL"
        }
    ],
    "__v": 0
}

If we want to update the student with this _id and one of the book title, we can do like this:

app.put('/students/:studentId', async (request, response) => {
    const { studentId } = request.params;
    const { title, finished } = request.body;

    const result = await Student.findOneAndUpdate(
        {
            _id: new mongoose.Types.ObjectId(studentId),
            'books.title': title,
        },
        {
            $set: {
                'books.$.finished': finished,
            },
        },
        {
            new: true,
        }
    );

    response.send(result);
});

Here I get the student id in the params, and the updated field in the request body, you can change this as you want.

Now if we send a request with this request body

{
    "title": "book 2 title",
    "finished": true
}

The result will be like this: (the finished property of the book with title 'book 2 title' updated to the true.

{
    "_id": "6314eda827c01a07746bceff",
    "name": "student 1",
    "books": [
        {
            "_id": "6314eda827c01a07746bcf00",
            "title": "book 1 title",
            "length": 1,
            "author": "book 1 author",
            "ISBN": "book 1 ISBN",
            "finished": true,
            "dueDate": "book 1 dueDate",
            "imgURL": "book 1 imgURL"
        },
        {
            "_id": "6314eda827c01a07746bcf01",
            "title": "book 2 title",
            "length": 2,
            "author": "book 2 author",
            "ISBN": "book 2 ISBN",
            "finished": true,
            "dueDate": "book 2 dueDate",
            "imgURL": "book 2 imgURL"
        }
    ],
    "__v": 0
}

You can send more fields in the request body and use in set.

  • Related