Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 367|回复: 0

MongoDB 执行mongoexport时异常及分析(关于数字类型的查询)

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-6-11 17:36:57 | 显示全部楼层 |阅读模式

    今天在用mongoexport导出满足一定条件下的数据时,遇到了一个报错,现纪录下来,并且针对此错误对MongoDB 的 数字类型 做了进一步的学习。

    背景 及 报错信息 

    今天接到一个业务需求,需要从MongoDB 数据库 order集合中导出符合以下条件的数据:

     

    db.qqwj_order.find({"Source":NumberInt("21"),"Batch":"支付中的订单提醒:2018/9/5","MsgContent":/还未完成在线付款/})

     

    通过MongoDB 客户端工具 【NoSQLBooster for MongoDB】查询检查,语句执行正常,显示相应记录数为 15265。

    导出数据使用mongoexport命令,执行命令如下:

    /data/mongodb/mongobin344/bin/mongoexport  -h 172.X.X.XXX --port 端口 --db 数据库 -u 账号 -p '密码' --authenticationDatabase 认证数据库 --type=csv -c qqwj_order -f MsgContent,REC_CreateTime  -q '{ "Source":NumberInt("21"),"Batch":"支付中的订单提醒:2018/9/5","MsgContent":/还未完成在线付款/}' -o  /data/mongodb_back/sms.csv 

    但是执行报错:

    XXX is not valid JSON: json: cannot unmarshal string into Go value of type json.NumberInt

    错误截图如下:

     

    错误推断及测试

     

    因为报错信息中NumberInt 关键字,此时去看我们的查询条件正好也有此关键字,所以推测 是不是这个问题。

    结果将导出命令中的 NumberInt("21") 直接替换为 21 ,再次执行。

    执行命令为 :

    /data/mongodb/mongobin344/bin/mongoexport  -h 172.X.X.XXX --port 端口 --db 数据库 -u 账号 -p '密码' --authenticationDatabase 认证数据库 --type=csv -c qqwj_order -f MsgContent,REC_CreateTime  -q '{"Source":21,"Batch":"支付中的订单提醒:2018/9/5","MsgContent":/还未完成在线付款/}' -o  /data/mongodb_back/sms.csv

     

    执行结果为

    结果表明修改后,数据成功导出

    错误解析与原理探究

     

    为什么通过查询器查看,数据就是     "Source" : NumberInt("21"),但是在shell 中的执行导出命令写成"Source" : NumberInt("21") 就会报错。而一定要转换为"Source":21

    查询器查询出的Source字段显示:

    明明就是 "Source" : NumberInt("21"),为什么复制到shell,执行报错???

     

    回头看,找原理。我们知道目前MongoDB 支持4中数据类型。

    • double
    • 32-bit integer
    • 64-bit integer
    • Decimal (New in version 3.4.)

     

    在MongoDB客户端可以执行查询,但是在shell中无法执行导出,那么会不会和这两种工具有关?会不会和插入的NumberInt(数字) 还是NumberInt('数字‘)有关?

    下面对假设进行验证测试。

    通过 NoSQLBooster for MongoDB 方式 插入测试数据

    通过 shell方式插入测试数据

     

    通过$type 去查看插入的数据类型

     

    1》执行db.numbers.find({n:{$type:1}})  // Type 为 Double;查询Type 为 Double的数据

    以上查询结果显示,不管是通过客户端还是shell,当数字不指明数据类型时,插入的数字数据默认都是Double。

     

     2》执行命令 db.numbers.find({n:{$type:16}})  // Type 为 32-bit integer ;查询Type 为 32-bit integer的数据

    以上查询表名,不管通过客户端还是shell,指定的NumberInt(5) 还是NumberInt('5‘) 后台都转成统一32-bit integer 类型存储了。

     

     3》执行命令 db.numbers.find({n:{$type:18}})  // Type 为 64-bit integer 查询Type 为 64-bit integer的数据

     

    以上查询表名,不管通过客户端还是shell,指定的NumberLong(5) 还是NumberLong('5') 后台都转成统一64-bit integer 类型存储了。

     

    以上的测试说明,当我们在存储数字数据时会自动转储(不管什么客户端工具,是shell还是 【NoSQLBooster for MongoDB】,不管 NumberLong(5) 还是NumberLong('5');NumberInt(5) 还是NumberInt('5‘))。

     

    有点糊涂了吧? 如此这样,那为什么 在查询是报错呢?

    回头再看错误提示:XXX is not valid JSON: json: cannot unmarshal string into Go value of type json.NumberInt

    其意思是shell 认为我们把一个字符类型的数据传给了 json.NumberInt。

    那我如果将导出命令中的 NumberInt("21") 将 换成 NumberInt(21)

    执行命令为 :

    /data/mongodb/mongobin344/bin/mongoexport  -h 172.X.X.XXX --port 端口 --db 数据库 -u 账号 -p '密码' --authenticationDatabase 认证数据库 --type=csv -c qqwj_order -f MsgContent,REC_CreateTime  -q '{"Source": NumberInt(21),"Batch":"支付中的订单提醒:2018/9/5","MsgContent":/还未完成在线付款/}' -o  /data/mongodb_back/sms.csv 

    执行也成功。

    结论

    说了很多总结下:

    执行失败的导出命令是:

    /data/mongodb/mongobin344/bin/mongoexport  -h 172.X.X.XXX --port 端口 --db 数据库 -u 账号 -p '密码' --authenticationDatabase 认证数据库 --type=csv -c qqwj_order -f MsgContent,REC_CreateTime  -q '{ "Source":NumberInt("21"),"Batch":"支付中的订单提醒:2018/9/5","MsgContent":/还未完成在线付款/}' -o  /data/mongodb_back/sms.csv 

    执行成功的导出命令是:

    /data/mongodb/mongobin344/bin/mongoexport  -h 172.X.X.XXX --port 端口 --db 数据库 -u 账号 -p '密码' --authenticationDatabase 认证数据库 --type=csv -c qqwj_order -f MsgContent,REC_CreateTime  -q '{"Source":21,"Batch":"支付中的订单提醒:2018/9/5","MsgContent":/还未完成在线付款/}' -o  /data/mongodb_back/sms.csv

    和 

    /data/mongodb/mongobin344/bin/mongoexport  -h 172.X.X.XXX --port 端口 --db 数据库 -u 账号 -p '密码' --authenticationDatabase 认证数据库 --type=csv -c qqwj_order -f MsgContent,REC_CreateTime  -q '{"Source": NumberInt(21),"Batch":"支付中的订单提醒:2018/9/5","MsgContent":/还未完成在线付款/}' -o  /data/mongodb_back/sms.csv 

    三个导出命令不同的地方已用红色字体标注。

     

    P.S  1  :后来作者深究了一下,为什么同样的查询,通样的查询结果,有的显示  "n" : 5  ; 有的显示 "n" : NumberInt("5")。嘻嘻 》》》》版本不同而已。

    旧版本(部分)的显示

    新版本(例如nosqlbooster4mongo-4.7.1)的显示

    P.S  2  :在存储数字数据时,到底会存储为何种数据类型,其实和语言的的驱动有关。例如在Ruby 和 Python 语言里在序列化整数时,驱动会自动确定是否编码为32-bit integer 还是 64-bit integer;shell 需要显示指定才可以。

     

    本文版权归作者所有,未经作者同意不得转载,谢谢配合!!!

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-1-23 05:59 , Processed in 0.062559 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表