MongoDB技术问题:如何更新已查询到的文档(电影评分系统场景)
电影评分系统中Content文档的正确更新方式
原代码存在的问题
- Content查询条件错误:原代码中
Content.findOne使用_id: document._id,这里把Rating文档的ID当成了Content的ID,应该替换为req.body.contentId(或document.contentId),因为Rating中存储的contentId才是对应Content的唯一标识。 - 平均分计算逻辑错误:原公式
(content.average + document.rating) / content.count + 1不符合加权平均的计算规则,正确逻辑应为**(当前总分 + 新评分)/ 新的评分次数**。 - 服务器错误状态码误用:服务器内部错误应返回
500而非404,404用于标识资源不存在。
修正方案一:直接修改文档对象并保存
这种方式直观易懂,适合低并发场景:
router.post('/', authenticate, async (req: IRequest<IRating>, res) => { try { const ratingDoc = await Rating.create({ contentId: req.body.contentId, contentType: req.body.contentType, rating: req.body.rating, review: req.body.review, userId: req.user?._id, }); // 修正查询条件,用内容ID查找对应的Content文档 const content = await Content.findOne({ type: req.body.contentType, _id: req.body.contentId, }); if (content) { // 计算新的评分次数和平均分 const newCount = content.count + 1; const newAverage = (content.average * content.count + ratingDoc.rating) / newCount; // 修改文档属性后直接保存 content.count = newCount; content.average = newAverage; await content.save(); } res.json({ success: true, rating: ratingDoc, content }); } catch (err) { // 修正服务器错误状态码 res.status(500).json({ success: false, message: '服务器错误' }); } });
修正方案二:原子更新(推荐高并发场景)
使用MongoDB的原子操作,在数据库层面保证操作的原子性,避免并发读写导致的数据不一致问题:
router.post('/', authenticate, async (req: IRequest<IRating>, res) => { try { const ratingDoc = await Rating.create({ contentId: req.body.contentId, contentType: req.body.contentType, rating: req.body.rating, review: req.body.review, userId: req.user?._id, }); // 原子更新Content文档,直接在数据库层面计算新的count和average const updatedContent = await Content.findOneAndUpdate( { type: req.body.contentType, _id: req.body.contentId, }, [ { $set: { count: { $add: ['$count', 1] }, average: { $divide: [ { $add: [{ $multiply: ['$average', '$count'] }, ratingDoc.rating] }, { $add: ['$count', 1] } ] } } } ], { new: true } // 配置返回更新后的文档 ); res.json({ success: true, rating: ratingDoc, content: updatedContent }); } catch (err) { res.status(500).json({ success: false, message: '服务器错误' }); } });
内容的提问来源于stack exchange,提问作者pvp11
相关产品推荐
相关产品推荐

