bson.errors.InvalidDocument: key '$numberDecimal' 在使用 json 时不能以 '$' 开头

pow*_*xie 6 python json mongodb bson

我有一个小的 json 文件,有以下几行:

{
    "IdTitulo": "Jaws",
    "IdDirector": "Steven Spielberg",
    "IdNumber": 8,
    "IdDecimal": "2.33"
}
Run Code Online (Sandbox Code Playgroud)

我的数据库集合中有一个模式,名为 test_dec。这是我用来创建架构的内容:

db.createCollection("test_dec",
{validator: {
    $jsonSchema: {
         bsonType: "object",
         required: ["IdTitulo","IdDirector"],
         properties: {
         IdTitulo: {
                "bsonType": "string",
                "description": "string type, nombre de la pelicula"
            },
         IdDirector: {
                "bsonType": "string",
                "description": "string type, nombre del director"
            },
        IdNumber : {
                "bsonType": "int",
                "description": "number type to test"
            },
        IdDecimal : {
                 "bsonType": "decimal",
                 "description": "decimal type"
                    }
       }
    }}
    })
Run Code Online (Sandbox Code Playgroud)

我已经多次尝试插入数据。问题出在 IdDecimal 字段值中。

一些试验,将 IdDecimal 行替换为:

 "IdDecimal": 2.33

 "IdDecimal": {"$numberDecimal": "2.33"}

 "IdDecimal": NumberDecimal("2.33")
Run Code Online (Sandbox Code Playgroud)

他们都没有工作。第二个是 MongoDB 手册 (mongodb-extended-json) 提供的正式解决方案,错误是我放在问题中的输出: bson.errors.InvalidDocument: key'$numberDecimal' must not start with '$' .

我目前正在使用 python 加载 json。我一直在玩这个文件:

import os,sys
import re
import io
import json
from pymongo import MongoClient
from bson.raw_bson import RawBSONDocument
from bson.json_util import CANONICAL_JSON_OPTIONS,dumps,loads
import bsonjs as bs

#connection
client = MongoClient('localhost',27018,document_class=RawBSONDocument)
db     = client['myDB']
coll   = db['test_dec']   
other_col = db['free']                                                                                        

for fname in os.listdir('/mnt/win/load'):                                                                               
    num = re.findall("\d+", fname)

    if num:

       with io.open(fname, encoding="ISO-8859-1") as f:

            doc_data = loads(dumps(f,json_options=CANONICAL_JSON_OPTIONS))

            print(doc_data) 

            test = '{"idTitulo":"La pelicula","idRelease":2019}'
            raw_bson = bs.loads(test)
            load_raw = RawBSONDocument(raw_bson)

            db.other_col.insert_one(load_raw)


client.close()
Run Code Online (Sandbox Code Playgroud)

我正在使用 json 文件。如果我尝试解析类似 Decimal128('2.33') 的任何内容,则输出为“ValueError:无法解码 JSON 对象”,因为我的 json 格式无效。

的结果

    db.other_col.insert_one(load_raw) 
Run Code Online (Sandbox Code Playgroud)

是插入了“测试”的内容。但是我不能将 doc_data 与 RawBSONDocument 一起使用,因为它就是这样。它说:

  TypeError: unpack_from() argument 1 must be string or buffer, not list:
Run Code Online (Sandbox Code Playgroud)

当我设法将 json 直接解析为 RawBSONDocument 时,我得到了所有垃圾,数据库中的记录看起来像这里的示例:

   {
    "_id" : ObjectId("5eb2920a34eea737626667c2"),
    "0" : "{\n",
    "1" : "\t\"IdTitulo\": \"Gremlins\",\n",
    "2" : "\t\"IdDirector\": \"Joe Dante\",\n",
    "3" : "\t\"IdNumber\": 6,\n",
    "4" : "\"IdDate\": {\"$date\": \"2010-06-18T:00.12:00Z\"}\t\n",
    "5" : "}\n"
     }
Run Code Online (Sandbox Code Playgroud)

将扩展的 json 加载到 MongoDB 中似乎并不那么简单。扩展版本是因为我想使用模式验证。

Oleg 指出这是 numberDecimal 而不是我之前使用的 NumberDecimal。我已经修复了 json 文件,但没有任何改变。

执行:

with io.open(fname, encoding="ISO-8859-1") as f:
      doc_data = json.load(f)                
      coll.insert(doc_data)
Run Code Online (Sandbox Code Playgroud)

和 json 文件:

 {
    "IdTitulo": "Gremlins",
    "IdDirector": "Joe Dante",
    "IdNumber": 6,
    "IdDecimal": {"$numberDecimal": "3.45"}
 }
Run Code Online (Sandbox Code Playgroud)

Bel*_*ter 3

我又掷了一骰子。如果您按原样使用模式验证,我建议定义一个类并明确定义每个字段以及您建议如何将字段转换为相关的 python 数据类型。虽然您的解决方案是通用的,但数据结构必须严格以匹配验证。

IMO 这更清楚,您可以控制课堂上的任何错误等。

只是为了确认我运行了架构验证并且这适用于提供的验证。

from pymongo import MongoClient
import bson.json_util
import dateutil.parser
import json

class Film:
    def __init__(self, file):
        data = file.read()
        loaded = json.loads(data)
        self.IdTitulo  = loaded.get('IdTitulo')
        self.IdDirector = loaded.get('IdDirector')
        self.IdDecimal = bson.json_util.Decimal128(loaded.get('IdDecimal'))
        self.IdNumber = int(loaded.get('IdNumber'))
        self.IdDateTime = dateutil.parser.parse(loaded.get('IdDateTime'))

    def insert_one(self, collection):
        collection.insert_one(self.__dict__)

client = MongoClient()
mycollection = client.mydatabase.test_dec

with open('c:/temp/1.json', 'r') as jfile:
    film = Film(jfile)
    film.insert_one(mycollection)
Run Code Online (Sandbox Code Playgroud)

给出:

> db.test_dec.findOne()
{
        "_id" : ObjectId("5eba79eabf951a15d32843ae"),
        "IdTitulo" : "Jaws",
        "IdDirector" : "Steven Spielberg",
        "IdDecimal" : NumberDecimal("2.33"),
        "IdNumber" : 8,
        "IdDateTime" : ISODate("2020-05-12T10:08:21Z")
}
Run Code Online (Sandbox Code Playgroud)

>

使用的 JSON 文件:

{
    "IdTitulo": "Jaws",
    "IdDirector": "Steven Spielberg",
    "IdNumber": 8,
    "IdDecimal": "2.33",
    "IdDateTime": "2020-05-12T11:08:21+0100"
}
Run Code Online (Sandbox Code Playgroud)