Reputation: 1440
I have the next document, and I want to update the addresses with id of 21, change the alias to 'Family'. I run User.update({ _id: 2, 'addresses._id': 21 }, { 'addresses.$': newAddress });
Which works fine, with an annoying side effect, is that Mongo generates a new id for the subdocument. Is there any way to update a subdocument without getting a new id?
'user': {
'_id': 2,
'addresses': [
{
'_id': '20',
'alias': 'Work',
'postal_code': 1235
},
{
'_id': '21',
'alias': 'Home',
'postal_code': 1235
}
]
}
I already solved this using
User.update(
{ _id: req.user._id, 'addresses._id': addressId },
{ $set: {
'addresses.$.alias': newAddress.alias,
'addresses.$.address': newAddress.address,
'addresses.$.areaId': newAddress.areaId,
'addresses.$.cityId': newAddress.cityId,
'addresses.$.postal_code': newAddress.postal_code
} }
);
This doesn't change the id of the subdocument, but I don't like this solution for obvious reasons.
Upvotes: 6
Views: 3676
Reputation: 1440
Adding to JasonCust's answer, the correct approach is to inject the old id into the new address to keep the id unchanged and avoid having to enter each individual key.
Below is an example:
const userSchema = new Schema({
addresses: [{ country: String }]
});
const User = mongoose.model('User', userSchema);
const user = await User.create({
addresses: [
{ country: 'Egypt' }
]
});
const oldAddressId = user.addresses[0]._id;
//
const newAddress = {
_id: oldAddressId,
country: 'Japan'
};
await User.updateOne({ 'addresses._id': oldAddressId }, { 'addresses.$': newAddress });
const userAfterUpdate = await User.findOne({ _id: user._id });
assert.equal(userAfterUpdate.addresses[0].country, 'Japan');
assert.equal(userAfterUpdate.addresses[0]._id.toString(), oldAddressId.toString());
Upvotes: 5
Reputation: 10909
The short answer is: no. In essence the update object { 'addresses.$': newAddress }
is a command to replace the entire object at the matched pointer location with the newAddress
object. That said, if the newAddress
object includes the _id
value then it should be stored as the value.
Upvotes: 4