You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mongoose触发Query was already executed报错,评论更新删除无法同步影片评分求助

问题原因

你遇到的Query was already executed报错,核心是Mongoose的查询实例是一次性的,你在pre(/^findOneAnd/)中间件里调用await this.findOne()已经把当前查询实例执行了一次,后面控制器里触发的findByIdAndUpdate底层属于findOneAndUpdate匹配规则,同一个查询实例执行两次就会触发该报错。

解决方案

1. 修改pre查询中间件

通过clone()方法克隆查询实例后再执行查询,避免污染原查询实例,同时把查询到的原始文档挂载到查询实例上方便后续使用:

reviewSchema.pre(/^findOneAnd/, async function(next) {
  // 克隆实例执行查询,不影响原查询逻辑
  this.reviewDoc = await this.clone().findOne();
  next();
});

2. 新增post查询中间件

在update/delete操作执行完成后,触发评分计算逻辑,覆盖更新、删除场景:

reviewSchema.post(/^findOneAnd/, async function() {
  await this.reviewDoc.constructor.calcAvgRating(this.reviewDoc.movie);
});

3. 补充聚合逻辑边界处理

当对应电影的所有评论都被删除时,聚合返回的结果是空数组,原代码会触发索引报错,补充判断逻辑:

reviewSchema.statics.calcAvgRating = async function(movieId) {
  const stats = await this.aggregate([
    {
      $match:{movie:movieId}
    },
    {
      $group:{
        _id:'$movie',
        nRating:{$sum:1},
        avgRating:{$avg:'$rating'}
      }
    }
  ])

  if (stats.length) {
    await movieModel.findByIdAndUpdate(movieId,{
      ratingsQuantity:stats[0].nRating,
      avgRating:stats[0].avgRating
    });
  } else {
    // 无评论时重置为默认值
    await movieModel.findByIdAndUpdate(movieId,{
      ratingsQuantity: 0,
      avgRating: 0
    });
  }
}

4. 控制器无需修改

原有updateOne控制器代码可以直接正常运行,不需要调整。

修改完成后新增评论、更新评论、删除评论都会自动同步更新对应电影的评分和评论数量字段,不会再触发查询重复执行报错。

内容的提问来源于stack exchange,提问作者harsh dixit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 18:45:03