Mongoose 5.0.15/MongoDB 3.6.4 coords字段转数组失败问题求助
问题分析
从你给出的错误日志和代码来看,核心问题主要有两个,还有一个容易忽略的细节:
- 请求体解析未配置:你用
application/x-www-form-urlencoded格式提交请求,但你的Express应用大概率没配置对应的body解析中间件,导致req.body是空对象。这直接引发了两个连锁问题:一是所有必填字段(比如name、openingTimes.days)都拿不到值,触发必填校验失败;二是parseFloat(req.body.lng)和parseFloat(req.body.lat)会得到NaN,进而触发coords的类型转换错误。 - coords字段类型不匹配:你的Schema里定义
coords是[[Number]](二维数组),但控制器里传的是一维数组[lng, lat],这和Mongoose的类型预期不匹配,就算参数能正确获取,也会触发转换失败。 - 布尔值参数的类型问题:Postman用urlencoded格式提交的
closed1是字符串类型(比如"false"),直接传给Mongoose会被当成true处理,也可能隐含校验问题。
解决方案
1. 先配置Express的body解析中间件
这是最关键的一步,否则所有参数都无法正确获取:
- 先安装依赖:
npm install body-parser --save
- 在你的主服务文件(比如
app.js/server.js)里添加配置:
const bodyParser = require('body-parser'); // 解析urlencoded格式的请求体 app.use(bodyParser.urlencoded({ extended: true })); // 顺便配置JSON解析,方便后续接口扩展 app.use(bodyParser.json());
2. 修正coords的Schema定义
针对2dsphere索引,Mongoose支持两种规范格式,选一种适合你的:
选项A:用GeoJSON Point格式(推荐,符合MongoDB官方规范)
修改locationSchema里的coords字段:
const locationSchema = new mongoose.Schema({ // ...其他字段 coords: { $type: { type: String, enum: ['Point'], required: true }, coordinates: { $type: [Number], required: true }, index: '2dsphere' }, // ...其他字段 }, {typeKey: "$type"});
然后在控制器里传递符合格式的数据:
coords: { type: 'Point', coordinates: [parseFloat(req.body.lng), parseFloat(req.body.lat)] },
选项B:用一维数组格式(简化版)
如果你想保持现有控制器的传参逻辑,把Schema里的coords改成一维数组:
coords: {$type: [Number], index: '2dsphere', required:true},
这样控制器里现有的coords: [parseFloat(req.body.lng), parseFloat(req.body.lat)]就能正常工作了。
3. 优化控制器的参数处理
增加参数校验,避免因参数缺失或格式错误导致的问题:
module.exports.locationsCreate = (req, res) => { // 校验必填参数是否存在 const requiredFields = ['name', 'lng', 'lat', 'days1', 'closed1']; const missingFields = requiredFields.filter(field => !req.body[field]); if (missingFields.length > 0) { return sendJsonResponse(res, 400, { message: `缺少必填字段:${missingFields.join(', ')}` }); } // 校验坐标是否为有效数字 const lng = parseFloat(req.body.lng); const lat = parseFloat(req.body.lat); if (isNaN(lng) || isNaN(lat)) { return sendJsonResponse(res, 400, { message: '坐标格式错误:lng和lat必须是有效数字' }); } // 处理facilities的字符串转数组 const facilities = req.body.facilities ? req.body.facilities.split(',') : []; // 处理布尔值字符串转布尔类型 const isClosed = req.body.closed1 === 'true'; Loc.create({ name: req.body.name, address: req.body.address, facilities: facilities, coords: [lng, lat], // 或者对应GeoJSON格式 openingTimes: [{ days: req.body.days1, opening: req.body.opening1, closing: req.body.closing1, closed: isClosed }] }, function (err, location){ if (err){ sendJsonResponse(res, 400, err); } else{ sendJsonResponse(res, 201, location); } }); };
测试验证
完成上述修改后重启服务器,用Postman提交之前的请求,应该就能正常创建Location文档了。
内容的提问来源于stack exchange,提问作者rags2riches-prog
相关产品推荐
相关产品推荐

