Mongoose Query中间件报Query has already execute错误求助
问题解决方法
报错原因
- Mongoose 6.0+ 版本默认禁止同一个查询实例重复执行,你在
pre(/^findOneAnd/)钩子中调用this.findOne()已经执行了一次查询,后续原findOneAndXXX(更新/删除类)操作要再次执行同一个查询实例就触发了Query was already executed报错。 - 你的
post(/^findOneAnd/)钩子中存在笔误,将评论关联的商品字段product错写为tour,会导致后续计算平均评分时传入的商品ID无效。 - 可选边界问题:当商品下所有评论都被删除时,聚合返回的
stats数组为空,直接取stats[0]会抛出空指针错误。
修复方案
1. 给pre钩子的findOne调用添加clone()
clone()方法会生成新的查询实例,避免和原查询的执行逻辑冲突:
reviewSchema.pre(/^findOneAnd/, async function (next) { this.r = await this.findOne().clone(); next(); });
2. 修正post钩子的字段笔误
把关联字段从错误的tour改为正确的product:
reviewSchema.post(/^findOneAnd/, async function () { const model = this.r.constructor; await model.calcAverageRatings(this.r.product); });
3. 优化calcAverageRatings的边界处理
增加空数组判断,避免删除所有评论时报错:
reviewSchema.statics.calcAverageRatings = async function (productId) { const stats = await this.aggregate([ { $match: { product: productId }, }, { $group: { _id: "$product", numRating: { $sum: 1 }, avgRating: { $avg: "$rating" }, }, }, ]); if (stats.length > 0) { await Product.findByIdAndUpdate(productId, { ratingsAverage: stats[0].avgRating, ratingsQuantity: stats[0].numRating, }); } else { // 无评论时重置为默认值 await Product.findByIdAndUpdate(productId, { ratingsAverage: 4.5, // 可替换为你的业务默认评分 ratingsQuantity: 0, }); } };
内容的提问来源于stack exchange,提问作者Muhmmad Akash
相关产品推荐
相关产品推荐

