web-dev-qa-db-ja.com

bson.errors.InvalidDocument:jsonを使用する場合、キー '$ numberDecimal'を '$'で始めることはできません

次の行を含む小さなjsonファイルがあります。

{
    "IdTitulo": "Jaws",
    "IdDirector": "Steven Spielberg",
    "IdNumber": 8,
    "IdDecimal": "2.33"
}

Test_decという名前のスキーマが私のdbコレクションにあります。これは私がスキーマを作成するために使用したものです:

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"
                    }
       }
    }}
    })

データの挿入を何度も試みました。問題はIdDecimalフィールド値にあります。

IdDecimal行を次のように置き換えて、いくつかのトライアル

 "IdDecimal": 2.33

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

 "IdDecimal": NumberDecimal("2.33")

それらのどれも動作しません。 2つ目は、MongoDBのマニュアル(mongodb-extended-json)によって提供される正式なソリューションであり、エラーは私が私の質問に入力した出力です:bson.errors.InvalidDocument:key 。

現在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()

私はjsonファイルを使用しています。 Decimal128( '2.33')のようなものを解析しようとすると、jsonの形式が無効なため、出力は「ValueError:JSONオブジェクトをデコードできませんでした」になります。

結果として

    db.other_col.insert_one(load_raw) 

「テスト」の内容が挿入されているということです。しかし、私はdoc_dataをRawBSONDocumentで使用することはできません。それは言う:

  TypeError: unpack_from() argument 1 must be string or buffer, not list:

RawBSONDocumentにjsonを直接解析できたとき、すべてのゴミがあり、データベースのレコードは次のサンプルのようになります。

   {
    "_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"
     }

拡張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)

そしてjsonファイル:

 {
    "IdTitulo": "Gremlins",
    "IdDirector": "Joe Dante",
    "IdNumber": 6,
    "IdDecimal": {"$numberDecimal": "3.45"}
 }
6
powerPixie

最後に、私はソリューションを手に入れました、そしてそれはRawBSONDocumentを使用しています。

最初にjsonファイル:

{
    "IdTitulo": "Dead Snow",
    "IdDirector": "Tommy Wirkola",
    "IdNumber": 11,
    "IdDecimal": {"$numberDecimal": "2.22"}
}

&検証スキーマファイル:

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"
                }
             }
          }}
   })

したがって、この場合のコレクションは「test_dec」です。

そして、pythonスクリプトは、ファイル「.json」を開き、それを読み取って解析し、MongoDBにインポートされます。

import json
from bson.raw_bson import RawBSONDocument
from pymongo import MongoClient
import bsonjs

#connection
client = MongoClient('localhost',27018)
db     = client['movieDB']
coll   = db['test_dec']

#open an read file
with open('1.json', 'r') as jfile:
    data = jfile.read()

    loaded = json.loads(data)
    dumped = json.dumps(loaded, indent=4)
    bson_bytes = bsonjs.loads(dumped)

    coll.insert_one(RawBSONDocument(bson_bytes))


client.close()

挿入されたドキュメント:

{
    "_id" : ObjectId("5eb971ec6fbab859dfae8a6f"),
    "IdTitulo" : "Dead Snow",
    "IdDirector" : "Toomy Wirkola",
    "IdDecimal" : NumberDecimal("2.22"),
    "IdNumber" : 11
 }

フィールドIdDecimalとIdNumberがどのように反転したかはわかりませんが、検証に合格し、本当に満足しています。

NumberDecimalの数値の代わりに「hello」を使用してドキュメントを試しましたが、挿入によって次の結果が得られました。

 {
    "_id" : ObjectId("5eb973b76fbab859dfae8ecd"),
    "IdTitulo" : "Shining",
    "IdDirector" : "Stanley Kubrick",
    "IdDecimal" : NumberDecimal("NaN"),
    "IdNumber" : 19
  }

助けてくれたすべてに感謝します。特にオレグ!!!とても我慢していただきありがとうございます。

0
powerPixie

bson.decimal128.Decimal128 を使用できませんか?何か不足していますか?

from pymongo import MongoClient
from bson.decimal128 import Decimal128

db = MongoClient()['mydatabase']

data = {
    "IdTitulo": "Jaws",
    "IdDirector": "Steven Spielberg",
    "IdNumber": 8,
    "IdDecimal": "2.33"
}

data['IdDecimal'] = Decimal128(data['IdDecimal'])
db.other_col.insert_one(data)
0
Belly Buster

タイプ情報を持つJSONは Extended JSON と呼ばれます。例に従って、データの拡張jsonを作成します。

ext_json = '''
{
    "IdTitulo": "Jaws",
    "IdDirector": "Steven Spielberg",
    "IdNumber": 8,
    "IdDecimal": {"$numberDecimal":"2.33"}
}
'''

Pythonでは、 json_util を使用して、拡張jsonをPython辞書にロードします。

from bson.json_util import loads

doc = loads(ext_json)

print(doc)

# {u'IdTitulo': u'Jaws', u'IdDirector': u'Steven Spielberg', u'IdDecimal': Decimal128('2.33'), u'IdNumber': 8}

このロードの結果は「BSONドキュメント」と呼ばれることもありますが、バイナリであるBSONではありません。このコンテキストでの「BSON」は、一部の値がpython標準ライブラリタイプではないことを意味します。「ドキュメント」の部分は、基本的にオブジェクトが辞書であることを意味します。

IdNumberが非標準のライブラリタイプであることがわかります。

print type(doc['IdDecimal'])

# <class 'bson.decimal128.Decimal128'>

この辞書をMongoDBに挿入するには、 pymongo tutorial に従ってください:

from pymongo import MongoClient
client = MongoClient('localhost', 14420)

db = client.test_database

collection = db.test_collection

collection.insert_one(doc)

print(doc)
0
Oleg