猫鼬更新多个子文档

时间:2018-09-20 20:16:21

标签: javascript node.js mongodb express mongoose

我正在尝试更新一个子文档addresses(有效),然后更新除上一个子文档以外的许多子文档。基本上,每次addressis_preferred更改为true时,都必须将is_preferredtrue的先前地址更新为false(我正在尝试更新所有人除了更改为true的地址)。

用户文档

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

这是我的解决方法:

// 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.'});
    }
});

我能够将user子文档addresses is_preferred更新为true。但是,将另一个addresses is_preferred更新为false无效。我究竟做错了什么?

1 个答案:

答案 0 :(得分:0)

对于像您这样的场景,我建议您使用猫鼬中间件let multiLineString = """ Line One Line Two Line Three """ pre模式挂钩。这个想法是,与其在您的控制器中处理该问题,不如通过该中间件在您的模式中进行处理。

唯一的不便之处是postpre钩子不会在post上触发,因此您需要先执行findOneAndUpdate然后执行find。 / p>

因此,您将对update挂钩执行以下操作:

post

要使更新生效,您需要执行以下操作:

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