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.