能否用单次Mongoose更新操作实现用户头像删除功能?
用单次MongoDB操作替代两次查询更新实现删除用户头像API
我正在开发一个用于删除用户头像(display picture,简称dp,为AWS S3链接字符串)的API接口,逻辑如下:
- 若用户
dp字段为空则不执行任何操作; - 若
dp字段有内容,则删除对应图片并将该字段更新为空。
以下是我当前的实现代码:
router.post('/deleteDP',jwtValid,function (req,res) { user.findById({'_id': req.decoded.id}, function (err, result) { if(err){return res.send("1");} //error else if(!result){return res.send("2");} //no user found else if(result) { if(result.dp === "") { ///send deleted res.send("0"); }else { // delete function for result.dp user.findByIdAndUpdate({'_id':result.id},{$set:{'dp':''}},function (err,result) { if(result){return res.send("0");} }); } } }); });
请问是否可以用单次MongoDB操作替代上述代码中的两次操作(findById和findByIdAndUpdate)来实现该功能?
当然可以!你完全可以通过单次MongoDB操作搞定这个需求,用findByIdAndUpdate就能把查询、条件判断和更新合并到一步完成,还能拿到更新前的头像链接去执行S3删除操作,既简化代码又提升性能。
修改后的实现代码
router.post('/deleteDP', jwtValid, async function (req, res) { const userId = req.decoded.id; // 单次操作:只匹配dp不为空的用户,更新后返回原始文档 user.findByIdAndUpdate( { _id: userId, dp: { $ne: "" } // 核心条件:只处理dp不为空的用户 }, { $set: { dp: "" } }, { returnOriginal: true }, // 确保拿到更新前的原始文档(包含旧的dp链接) async (err, oldDoc) => { if (err) { return res.send("1"); // 数据库错误 } if (!oldDoc) { // 两种可能:用户不存在,或者用户的dp本来就是空的 // 如果你需要严格区分这两种场景,可以先单独查用户是否存在 // const userExists = await user.exists({ _id: userId }); // return userExists ? res.send("0") : res.send("2"); // 业务允许的话,直接返回0也符合你原逻辑的预期 return res.send("0"); } // 这里调用你的S3删除函数,用oldDoc.dp拿到原始链接 try { // await deleteFromS3(oldDoc.dp); // 替换成你实际的S3删除方法 } catch (s3Err) { // 可选:如果S3删除失败,可以回滚用户的dp字段 // await user.findByIdAndUpdate(userId, { $set: { dp: oldDoc.dp } }); // return res.send("3"); // 自定义S3删除错误码 } res.send("0"); } ); });
关键逻辑说明
- 精准匹配条件:通过
dp: { $ne: "" }限定只对dp不为空的用户执行更新,这样如果用户头像本来就是空的,这次操作不会修改任何数据,oldDoc会返回null,刚好对应你原逻辑里“不执行操作”的场景。 - 获取原始数据:设置
returnOriginal: true能拿到更新前的文档,这样你就能直接用里面的dp值去调用S3的删除接口,不用额外查询一次。 - 灵活的错误区分:如果业务需要严格区分“用户不存在”和“dp为空”,可以加一次
user.exists查询,但如果不需要的话,直接返回统一状态码也完全符合需求。 - 异步处理S3操作:因为S3删除是异步任务,建议用
async/await包裹,避免出现还没删完就返回响应的情况,同时可以考虑删除失败时的回滚逻辑,保证数据一致性。
这样修改后,就把原来的两次MongoDB操作合并成了一次,代码更简洁,性能也更好。
内容的提问来源于stack exchange,提问作者Sonic_
相关产品推荐
相关产品推荐

