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

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);
解决方案

你的代码存在几个关键问题,逐个修正即可实现需求:

  1. 路径错误:Schema里没有items字段,直接操作rating数组即可,不需要加items.前缀;
  2. 更新操作符错误:更新已有rating的rate字段应该用$set,$push是用来往数组添加新元素的;
  3. 逻辑流程错误:需要先尝试更新已有用户的评分,若未找到匹配项,再执行新增操作。

修正后的代码(基础版)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 05:40:22