I am new to mongoose and I have a problem when I try to partially update my subdocument. Although I use the $set
operator, it resets the other fields even though they are not specified. I have noticed that sometimes it seems to work and sometimes it doesn't. I haven't been able to find a pattern. I need my update to be short.
This is my my schema.
import { Schema, model } from "mongoose";
const Path = Schema({
original: { type: String, required: true },
tiny: { type: String },
small: { type: String },
medium: { type: String },
large: { type: String },
extra_large: { type: String },
});
const BusinessPictureSchema = Schema({
Path: {
type: Path,
required: true
},
is_valid: {
type: Boolean,
required: true,
default: false
},
date_validation: {
type: Date
}
}, {
timestamps: true
});
module.exports = model('BusinessPicture', BusinessPictureSchema)
My test function:
async BusinessPicture() {
const input_create = {
Path: {
original: "original file",
tiny: "arhivo tiny"
}
}
const newBusinessPicture = new BusinessPicture(input_create);
await newBusinessPicture.save();
const input_update = {
Path: {
original: "new original file!!!"
}
}
await BusinessPicture.findByIdAndUpdate(newBusinessPicture.id, { $set: input_update });
return BusinessPicture;
// What i get
// {
// "Path": {
// "original": "original file",
// "_id": {
// "$oid": "6347a31784167896b62648e5"
// }
// },
// "is_valid": false,
// "createdAt": {
// "$date": {
// "$numberLong": "1665639182788"
// }
// },
// "updatedAt": {
// "$date": {
// "$numberLong": "1665639191235"
// }
// },
// "__v": 0
// }
// What i hope to find
// {
// "Path": {
// "original": "new original file!!",
// "tiny": "arhivo tiny", <----THISSSS
// "_id": {
// "$oid": "6347a4201829a87212b7c120"
// }
// },
// "is_valid": false,
// "createdAt": {
// "$date": {
// "$numberLong": "1665639452549"
// }
// },
// "updatedAt": {
// "$date": {
// "$numberLong": "1665639456805"
// }
// },
// "__v": 0
// }
}
CodePudding user response:
Basically what mongoose is doing under the hood is:
- search for operators (like $set).
- inside value passed to operator search for other operators. When nothing is found mongoose will interpret the key as a document key and it's value as the document value of this key.
When you pass
{
Path: {
original: "new original file!!!"
}
}
to $set
operator, it will interpret this as: Set the document value of key Path
to a this new object.
What you should do to achieve only adjusting the original
attribute:
await BusinessPicture.findByIdAndUpdate(newBusinessPicture.id, {
$set: {
'Path.original': "new original file!!!"
}
});