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

在Node.js+Express环境下,如何实现向MongoDB文档数组添加对象并解决update is not a function错误?

Fixing 'update is not a function' Error When Adding Reviews to MongoDB Documents

Let's break down what's going wrong here and fix it step by step:

Why You're Seeing the Error

The update is not a function error happens because await music.findOne(query) returns a single MongoDB document object (or null if no match is found) — this document doesn't have an update method. The update method belongs to the collection object, not individual documents.

Plus, there's a small mismatch between your request body and Mongoose Schema that we need to fix: your request uses a text field for the comment, but your Schema defines it as comment.

Solution 1: Using Native MongoDB Driver

If you want to stick with the native MongoDB driver approach in your code, here's the corrected route:

app.post('/addReview/:id', async (req, res) => {
  let idNumber = parseInt(req.params.id);
  
  // Fix the field mismatch and ensure correct data types
  const reviewObject = {
    id: parseInt(req.body.id), // Convert to number to match Schema
    locale: req.body.locale,
    rating: parseInt(req.body.rating),
    comment: req.body.text // Map 'text' from request to 'comment' in Schema
  };

  try {
    const musicCollection = client.db('database').collection('music');
    const query = { id: idNumber };

    // Use updateOne on the collection, not the retrieved document
    const result = await musicCollection.updateOne(
      query,
      { $push: { reviews: reviewObject } },
      { upsert: false } // Set to true if you want to create a new doc if none exists
    );

    if (result.matchedCount === 0) {
      return res.status(404).json({ message: "Music entry not found" });
    }

    res.status(200).json({ message: "Review added successfully" });
  } catch (err) {
    console.error(err);
    res.status(500).json({ message: "Failed to add review", error: err.message });
  }
});

Key Notes for This Approach:

  • $push handles both cases: If the reviews field doesn't exist on the document, $push will automatically create a new array and add your review object to it. If the field already exists, it appends the object to the existing array — exactly what you need.
  • We converted fields like id and rating to numbers to match your Schema's type requirements.
  • The upsert: false option ensures we don't create a new music document if the requested id doesn't exist (change to true if you want that behavior).

Solution 2: Using Mongoose Model (Cleaner & Safer)

Since you already defined a Mongoose Schema and Model for Music, using it will give you automatic data validation and cleaner code:

First, make sure you import your Music model at the top of your route file:

const Music = require('./path/to/your/musicModel'); // Update the path to your model file

Then rewrite the route:

app.post('/addReview/:id', async (req, res) => {
  let idNumber = parseInt(req.params.id);
  
  // Prepare review data to match Schema
  const reviewData = {
    id: parseInt(req.body.id),
    locale: req.body.locale,
    rating: parseInt(req.body.rating),
    comment: req.body.text
  };

  try {
    // Use findOneAndUpdate for atomic, validated updates
    const updatedMusic = await Music.findOneAndUpdate(
      { id: idNumber },
      { $push: { reviews: reviewData } },
      { 
        new: true, // Return the updated document instead of the original
        runValidators: true, // Enforce Schema validation on the review data
        upsert: false 
      }
    );

    if (!updatedMusic) {
      return res.status(404).json({ message: "Music entry not found" });
    }

    res.status(200).json({ 
      message: "Review added successfully", 
      data: updatedMusic 
    });
  } catch (err) {
    console.error(err);
    res.status(500).json({ 
      message: "Failed to add review", 
      error: err.message 
    });
  }
});

Why This Is Better:

  • Automatic Validation: The runValidators: true option ensures your review data matches the Schema rules (e.g., no missing required fields, correct data types).
  • Atomic Operation: findOneAndUpdate handles the lookup and update in a single atomic step, which is safer than separate findOne and update calls.
  • Cleaner Response: The new: true option lets you return the updated document directly to the client.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 15:34:07