简体   繁体   中英

Mongoose update multiple subdocuments

I'm trying to update one subdocument addresses (works) and then update many subdocuments except the previous one. Basically every time an address change is_preferred to true, it must update the previous address that is_preferred was true to false (i'm trying to update everyone except the address that changed to true).

User document

 _id: ObjectId("5b996f0fd5fbf511709f668f"); addresses: [ { _id: ObjectId("5ba33e0991cd7a3bb85dab7e"); is_preferred:true }, { _id: ObjectId("5ba3e9337310c637207b44cb"); is_preferred:false } ] 

Here is my solution:

 // model User = mongoose.model('user', new Schema({ _id: { type: mongoose.Schema.Types.ObjectId, required: true }, addresses: [ { _id: { type: mongoose.Schema.Types.ObjectId, required: true }, is_preferred: { type: Boolean, required: true } } ], }, { collection: 'user' });); // route router.put('/updateAddress/:addressId', auth, user.updateAddress); // user.js exports.updateAddress = wrap(async(req, res, next) => { // update one object address `is_preferred` to true and return an array 'addresses' containing it const user = await User.findOneAndUpdate( { addresses: { $elemMatch: { _id: mongoose.Types.ObjectId(req.params.addressId) } } }, { 'addresses.$': req.body }, { projection: { addresses: { $elemMatch: { _id: mongoose.Types.ObjectId(req.params.addressId) } } }, new: true }).lean(); if (user) { // updated object `is_preferred` changed to true, so another objects must be false if (user.addresses[0].is_preferred) { // doesnt work await User.update({ _id: { $ne: mongoose.Types.ObjectId(req.params.addressId) }, is_preferred: true }, { $set: { addresses: { is_preferred: false } } }, { multi: true }); } res.status(200).json({success: true, message: 'Saved.', new_object: user.addresses[0]}); } else { res.status(400).json({success: false, message: 'Error.'}); } }); 

I'm able to update the user subdocument addresses is_preferred to true . However updating another addresses is_preferred to false isn't working. What Am I doing wrong?

I would recommend for a scenario like yours to utilize the mongoose middleware pre or post schema hooks. The idea is that instead of dealing with this in your controller you would take care of it in your schema via that middleware.

The only inconvenience is that the pre and post hooks do not fire on findOneAndUpdate and you would need to do first find then update .

So you would do something like this for the post hook:

User.post('save', doc => {
  // You can update all the rest of the addresses here.
});

Also for your update to work you need to do something like this:

User.update(
   { "addresses._id": { $ne: mongoose.Types.ObjectId(req.params.addressId) }}, 
   { $set: { 'addresses.0.is_preferred': false }}, 
   { multi: true }
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM