Search code examples
mongodbmongoosevalidationerror

Mongoose showing error : "ValidationError: Product validation failed: name: Cast to string failed for....."


I have a code where a schema for storing information about product has been defined followed by the code to add product information. Here is the code:

const Product=mongoose.model("Product", {
    id:{
        type: Number, 
        required: true,
    },
    name:{
        type: String,
        required: true,
    },
    image:{
        type: String,
        required: true,
    },
    category:{
        type: String,
        required: true,
    },
    new_price:{
        type: Number,
        required: true,
    },
    old_price:{
        type: Number,
        required: true,
    },
    date:{
        type: Date,
        default: Date.now,
    },
    available:{
        type: Boolean,
        default: true,
    },
})

app.post('/addproduct', async (req, res)=>{
    let products = await Product.find({});
    let id;
    if (products.length>0){
        let last_product_array = products.slice(-1);
        let last_product = last_product_array[0];
        id = last_product.id+1;
    }
    else{
        id=1;
    }
    const product = new Product({
        id: id,
        name: req.body.name,
        image: req.body.image,
        category: req.body.category,
        new_price: req.body.new_price,
        old_price: req.body.old_price,
    });
    console.log(product);
    await product.save();
    console.log("Saved");
    res.json({
        success: true,
        name: req.body.name,
    })
})

Here is the code from front-end where I am making the request:

    const AddProduct = () => {

  const [image, setImage] = useState(false);
  const [productDetails, setProductDetails] = useState({
    name:"",
    image: "",
    category: "women",
    new_price:"",
    old_price: ""
  })

  const imageHandler = (e)=>{
     setImage(e.target.files[0]);

  }
  const changeHandler = (e) =>{
    setProductDetails({...productDetails, [e.target.name]:[e.target.value]})
  }

  const Add_Product = async () =>{
        console.log(productDetails)
        
        let responseData;
        let product = productDetails;

        let formData = new FormData();
        formData.append('product', image);
        await fetch('http://localhost:4000/upload',{
            method: 'POST',
            headers: {
                Accept: 'application/json',
            },
            body: formData,
        }).then((resp)=>resp.json()).then((data)=>{responseData=data});
        if (responseData.success)
        {
            product.image=responseData.image_url;
            console.log(product);
            
            await fetch('http://localhost:4000/addproduct', {
                method: 'POST',
                headers:{
                    Accept:'application/json',
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(product),
            }).then((resp)=>resp.json()).then((data)=>{
                data.success?alert("Product added"):alert("Failed")
            })
        }
        
  }

  return (
    <div className='add-product'>
        <div className='addproduct-itemfield'>
            <p>Product title</p>
            <input value={productDetails.name} onChange={changeHandler} type="text" name='name' placeholder='Type here'/>
        </div>
        <div className='addproduct-price'>
            <div className='addproduct-itemfield'>
                <p>Price</p>
                <input value={productDetails.old_price} onChange={changeHandler} type="text" name='old_price' placeholder='Type here'/>
            </div>
            <div className='addproduct-itemfield'>
                <p>Offer Price</p>
                <input value={productDetails.new_price} onChange={changeHandler} type="text" name='new_price' placeholder='Type here'/>
            </div>
        </div>
        <div className='addproduct-itemfield'>
            <p>Product Category</p>
            <select value={productDetails.category} onChange={changeHandler} name='category' className='add-product-selector'>
                <option value="women">Women</option>
                <option value="men">Men</option>
                <option value="kids">Kids</option>
            </select>
        </div>
        <div className='addproduct-itemfield'>
            <label htmlFor='file-input'>
                <img src = {image?URL.createObjectURL(image):upload_area} className='addproduct-thumbnail-img' alt= ""/>
            </label>
            <input onChange={imageHandler} type="file" name='image' id='file-input' hidden/>
        </div>
        <button onClick={()=>{Add_Product()}} className='addproduct-btn'>ADD</button>
    </div>
  )
}

export default AddProduct

While executing the code, it is generating the following error:

this.$__.validationError = new ValidationError(this);
                               ^
ValidationError: Product validation failed: name: Cast to string failed for value "[ 'kids357' ]" (type Array) at path "name", category: Cast to string failed for value "[ 'kids' ]" (type Array) at path "category", new_price: Cast to Number failed for value "[ '65' ]" (type Array) at path "new_price", old_price: Cast to Number failed for value "[ '100' ]" (type Array) at path "old_price"
    at Document.invalidate (C:\Users\rafiz\Documents\Learning\ReactJS\E-Commerce\backend\node_modules\mongoose\lib\document.js:3201:32)       
    at model.$set (C:\Users\rafiz\Documents\Learning\ReactJS\E-Commerce\backend\node_modules\mongoose\lib\document.js:1460:12)
    at model.$set (C:\Users\rafiz\Documents\Learning\ReactJS\E-Commerce\backend\node_modules\mongoose\lib\document.js:1115:16)
    at model.Document (C:\Users\rafiz\Documents\Learning\ReactJS\E-Commerce\backend\node_modules\mongoose\lib\document.js:166:12)
    at model.Model (C:\Users\rafiz\Documents\Learning\ReactJS\E-Commerce\backend\node_modules\mongoose\lib\model.js:131:12)
    at new model (C:\Users\rafiz\Documents\Learning\ReactJS\E-Commerce\backend\node_modules\mongoose\lib\model.js:4700:15)
    at C:\Users\rafiz\Documents\Learning\ReactJS\E-Commerce\backend\index.js:87:21
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) 
.
.
.
.
{
        generatedMessage: true,
        code: 'ERR_ASSERTION',
        actual: false,
        expected: true,
        operator: '=='
      },
      valueType: 'Array'
    }
  },
  _message: 'Product validation failed'

How to resolve this error?

I tried to write code for admin panel of a e-commerce website. It should insert the product information into MongoDB collection.


Solution

  • From the error you have added, it seems like the payload you have passed is incorrect since all the values are coming into an array format. You have specified string for a name, but the value it received is array. And that goes for all the fields. Do check the req.body for the payload received from the client side.

    Also a small change in your code. It seems you're adding 1 to the id field. Instead of going through the array.length, you can use countDocuments() to get the count. Optionally, since you're already storing id of the item, you can get the id of the last document added and do +1 on it.

    The _id field consists of timestamp, which can be used to fetch the last document. 1 is used for sorting in ascending and -1 for descending.

        let product = await Product.find({}).sort({_id: -1});
        let id = product.id + 1
        
    

    Sorting in Mongo

    ObjectId in Mongo

    EDIT

    I checked your code and there is a mistake in the changeHandler function. You have to pass value to the key without wrapping it in an array. You just need to pass the key name in array brackets to get the name of the key. Your change should look like this.

    const changeHandler = (e) => {
        setProductDetails({ ...productDetails, [e.target.name]: e.target.value });
      };
    

    Objects-Square Brackets