使用Mongoose为单个Game存储多分类时遇验证错误,求原因解析
解决Mongoose中Game的category字段Cast to Array失败问题
这个错误的原因很明确:你的Mongoose Schema定义和前端传递的数据类型不匹配。
错误根源分析
你在gameSchema里把category字段定义成了ObjectId数组:
category: [{ type: Schema.Types.ObjectId, ref: 'category' }]
但前端通过多选框提交的是分类的title字符串数组(比如['ACTION','MOBILE','RPG']),Mongoose无法把普通字符串直接转换成MongoDB的ObjectId类型,因此抛出了ValidationError: Cast to Array failed的错误。
两种解决方案
根据你的需求,你可以选择下面任意一种方式来修复:
方案1:前端直接传递分类的ObjectId(推荐)
修改Handlebars模板里的<option>标签,把value属性从分类的title改成_id——这是后端Schema期望的类型:
<label for="category">Category</label> <select multiple name="category" id="category" class="cat form-control"> {{#select game.category}} {{#each categories}} <option value="{{_id}}">{{title}}</option> {{/each}} {{/select}} </select>
这样前端提交的就是分类文档的ObjectId数组,后端直接赋值给newGame.category就能正常保存了。另外注意调整你的save错误处理逻辑,更推荐用.catch()来捕获Promise错误:
const newGame = new Game({ title: req.body.title, description: req.body.postDescription, category: req.body.category, }); newGame.save() .then(() => { req.flash('success-message', 'New Game Created'); res.redirect('/admin/games'); }) .catch(err => { console.log(err); // 这里可以添加错误反馈给前端的逻辑 });
方案2:后端根据分类名称查询ObjectId再保存
如果因为业务限制,前端必须传递分类名称,那后端需要先根据名称找到对应的分类文档,提取它们的ObjectId后再赋值给Game:
// 先根据前端传的名称数组查询所有匹配的分类 Category.find({ title: { $in: req.body.category } }) .then(categories => { // 提取分类的ObjectId组成数组 const categoryIds = categories.map(category => category._id); // 创建Game实例并赋值 const newGame = new Game({ title: req.body.title, description: req.body.postDescription, category: categoryIds }); return newGame.save(); }) .then(() => { req.flash('success-message', 'New Game Created'); res.redirect('/admin/games'); }) .catch(err => { console.log(err); });
内容的提问来源于stack exchange,提问作者Trần Liêm
相关产品推荐
相关产品推荐

