Mongoose更新子文档报错:找不到schema路径的问题求助
问题描述
现有数据结构
{ "items": [ { "_id": "63a48f12a9731cfd8a64b0b1", "item_name": "addidas shoes", "__v": 0, "rating": [ { "_id": "63a48fd51fb70775d216eb87", "rate": 1, "user_id": "6398a1a157d6146413b23b43" } ] } ] }
需求
实现逻辑:若rating数组中已存在指定user_id的对象,则更新其rate字段;若不存在,则新增一个rating对象。
错误代码
const addRating = async (req, res) => { const { rate, user_id, item_id } = req.body; // item_id = 63a48f12a9731cfd8a64b0b1 user_id = 6398a1a157d6146413b23b43 rate = 6 // Adding ratings to the selected item const test = await itemDB.item.updateOne( { _id: item_id, rating: { user_id: user_id } }, { $push: { "items.rating.$[i].rate": rate } }, { arrayFilters: [{ "i.user_id": user_id }], upsert: true } ); console.log(test); res.json({ message: "success" }); };
错误信息
\node_modules\mongoose\lib\helpers\update\castArrayFilters.js:74 throw new Error(`Could not find path "${filterPath}" in schema`); ^ Error: Could not find path "items.rating.0.user_id" in schema
Schema定义
const mongoose = require("mongoose"); const RateSchema = mongoose.Schema({ rate: { type: Number, required: true, }, user_id: { type: mongoose.ObjectId, }, item_id: { type: mongoose.ObjectId, }, }); const ItemSchema = mongoose.Schema({ item_name: { type: String, required: true, }, rating: { type: [RateSchema], }, }); module.exports = mongoose.model("Items", ItemSchema);
解决方案
你的代码存在几个关键问题,逐个修正即可实现需求:
- 路径错误:Schema里没有
items字段,直接操作rating数组即可,不需要加items.前缀; - 更新操作符错误:更新已有rating的
rate字段应该用$set,$push是用来往数组添加新元素的; - 逻辑流程错误:需要先尝试更新已有用户的评分,若未找到匹配项,再执行新增操作。
修正后的代码(基础版)
const addRating = async (req, res) => { const { rate, user_id, item_id } = req.body; // 先尝试更新已有用户的评分 const updateResult = await itemDB.item.updateOne( { _id: item_id, "rating.user_id": user_id }, { $set: { "rating.$.rate": rate } } ); // 如果没有匹配到文档,说明该用户未评分过,执行新增 if (updateResult.matchedCount === 0) { await itemDB.item.updateOne( { _id: item_id }, { $push: { rating: { rate, user_id, item_id } } } ); } res.json({ message: "success" }); };
优化版(单次数据库请求)
用bulkWrite把两个操作合并成一次数据库请求,减少IO开销:
const addRating = async (req, res) => { const { rate, user_id, item_id } = req.body; await itemDB.item.bulkWrite([ { updateOne: { filter: { _id: item_id, "rating.user_id": user_id }, update: { $set: { "rating.$.rate": rate } } } }, { updateOne: { filter: { _id: item_id, "rating.user_id": { $ne: user_id } }, update: { $push: { rating: { rate, user_id, item_id } } }, upsert: true } } ]); res.json({ message: "success" }); };
关键说明
- 用
"rating.user_id": user_id匹配数组中包含指定用户ID的元素,通过$操作符定位到匹配的数组元素进行更新; matchedCount用于判断是否有匹配的文档,以此决定执行更新还是新增;bulkWrite可合并多个操作,减少数据库交互次数,提升性能。
内容的提问来源于stack exchange,提问作者Exzia
相关产品推荐
相关产品推荐

