一、问题描述
通过NodeJs操作MongoDb数据库,在删除操作中使用主键id做为条件:
有接触过mongodb的都知道这里的id是要传入ObjectId对象的,不能直接传字符串类型。
但是我在此处将字符串id转换成ObjectId时,却报如下错误:
UnhandledPromiseRejectionWarning: Error: Argument passed in must be
a single String of 12 bytes or a string of 24 hex characters
二、问题分析
查询官网,可以通过以下几种方式将String转换为ObjectId:
1、使用ObjectId(id)
2、使用new ObjectId(id)
3、使用静态方法ObjectId.createFromHexString(id)
然而使用以上三种方法依然出现上述错误。
但是直接使用id变量的值"5c640413d63e990b8478f6fd"来转换时是正常的:
deleteOne({_id:ObjectId("5c640413d63e990b8478f6fd")})
难道id变量和常量有什么不同吗?打印id变量类型,确实为string,显示的字符串内容也一样。
查看错误提示,代码调用堆栈如下:
找到objectid.js对应源码:
可以看到是长度不对。
打印id变量长度,以及各个字符值:
id变量字符串开头和结尾各多了一对单引号,这是怎么来的呢?
于是理一下数据流程,从数据源头开始查找。最早这个id是从数据库中查找的,经调试此时还是object类型,且转成string类型后长度是24,说明这时候是正常的。之后在界面中使用模板时传递参数过程出现了数据转换:
1、界面 home.art:
<a href='delete_interface/<%=items[i]._id %>'>
经测试此时_id转成string长度还是24
2、接口映射 app.js:
app.get('/delete_interface/:id',delete_interface)
经测试此时传入delete_interface的参数id字符串长度为26,数据转换过程中发生了变化!
三、问题解决
模板代码中在传递参数前将id变量从object类型转换成string类型
<a href='delete_interface/<%=items[i]._id.toString() %>'>
测试传入delete_interface的参数id字符串长度为24,数据库删除操作没有再报错,问题解决。
需要注意要在传参前进行类型转换,在delete_interface拿到参数后再进行转换是没用的。
四、总结
分析问题时,
1、不要被表面现象迷惑,比如查看id字符串内容看不出问题,但是查看长度及字符ascii码则明显能看出来
2、查看错误日志,分析错误堆栈,查看源码
3、分析代码和数据经过流程