1. 程式人生 > 資料庫 >MongoDB執行mongoexport時的異常及分析(數字型別的查詢)

MongoDB執行mongoexport時的異常及分析(數字型別的查詢)

概述

mongoexport命令列用於資料的匯出,預設匯出的檔案格式為JSON格式。當然也可以指定特定的檔案格式。

語法

C:\mongo\bin>mongoexport -help
options:
--help produce help message
-v [ --verbose ] be more verbose (include multiple times for more
verbosity e.g. -vvvvv)
-h [ --host ] arg mongo host to connect to ( <set name>/s1,s2 for sets)

--port arg server port. Can also use --host hostname:port
--ipv6 enable IPv6 support (disabled by default)
-u [ --username ] arg username
-p [ --password ] arg password
--dbpath arg directly access mongod database files in the given
path,instead of connecting to a mongod server -
needs to lock the data directory,so cannot be used
if a mongod is currently accessing the same path
--directoryperdb if dbpath specified,each db is in a separate
directory
-d [ --db ] arg database to use
-c [ --collection ] arg collection to use (some commands)
-f [ --fields ] arg comma separated list of field names e.g. -f name,age
--fieldFile arg file with fields names - 1 per line
-q [ --query ] arg query filter,as a JSON string
--csv export to csv instead of json
-o [ --out ] arg output file; if not specified,stdout is used
--jsonArray output to a json array rather than one object per
Line

說明:

  • -h:資料庫宿主機的IP
  • -u:資料庫使用者名稱
  • -p:資料庫密碼
  • -d:資料庫名字
  • -c:集合的名字
  • -f:匯出的列名
  • -q:匯出資料的過濾條件
  • --csv:匯出格式為csv

引言

今天在用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"),"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,"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),"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,"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,"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,"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 需要顯示指定才可以。+

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對我們的支援。