TypeError : ObjectId ( '')는 JSON 화 가능하지 않습니다.
Python을 사용하여 문서에서 가지고있는 함수를 쿼리 한 후 MongoDB에서 내 응답을 반환하면 유효한 응답이 반환되고 인쇄 할 수는 반환 할 수 없습니다.
오류 :
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
인쇄 :
{'result': [{'_id': ObjectId('51948e86c25f4b1d1c0d303c'), 'api_calls_with_key': 4, 'api_calls_per_day': 0.375, 'api_calls_total': 6, 'api_calls_without_key': 2}], 'ok': 1.0}
하지만 돌아 오려고 할 때 :
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
RESTfull 호출입니다.
@appv1.route('/v1/analytics')
def get_api_analytics():
# get handle to collections in MongoDB
statistics = sldb.statistics
objectid = ObjectId("51948e86c25f4b1d1c0d303c")
analytics = statistics.aggregate([
{'$match': {'owner': objectid}},
{'$project': {'owner': "$owner",
'api_calls_with_key': {'$cond': [{'$eq': ["$apikey", None]}, 0, 1]},
'api_calls_without_key': {'$cond': [{'$ne': ["$apikey", None]}, 0, 1]}
}},
{'$group': {'_id': "$owner",
'api_calls_with_key': {'$sum': "$api_calls_with_key"},
'api_calls_without_key': {'$sum': "$api_calls_without_key"}
}},
{'$project': {'api_calls_with_key': "$api_calls_with_key",
'api_calls_without_key': "$api_calls_without_key",
'api_calls_total': {'$add': ["$api_calls_with_key", "$api_calls_without_key"]},
'api_calls_per_day': {'$divide': [{'$add': ["$api_calls_with_key", "$api_calls_without_key"]}, {'$dayOfMonth': datetime.now()}]},
}}
])
print(analytics)
return analytics
db가 잘 연결되어 있고 컬렉션도 있고 유효한 결과를 얻었습니다. Json 오류가 발생합니다. 응답을 JSON으로 다시 변환하는 방법에 대한 아이디어. 감사합니다
자신이 소유 하고 사용하는 것을 정의해야 합니다.JSONEncoder
import json
from bson import ObjectId
class JSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, ObjectId):
return str(o)
return json.JSONEncoder.default(self, o)
JSONEncoder().encode(analytics)
다음과 같은 방법으로 사용할 수 있습니다.
json.encode(analytics, cls=JSONEncoder)
Pymongo가 제공 json_util- 당신이 핸들 BSON 유형에 대신에 하나를 사용할 수 있습니다.
>>> from bson import Binary, Code
>>> from bson.json_util import dumps
>>> dumps([{'foo': [1, 2]},
... {'bar': {'hello': 'world'}},
... {'code': Code("function x() { return 1; }")},
... {'bin': Binary("")}])
'[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }", "$scope": {}}}, {"bin": {"$binary": "AQIDBA==", "$type": "00"}}]'
json_util의 실제 예 .
Flask의 jsonify와 달리 "dumps"는 먹을 것을 반환하지 않습니다. Flask의 jsonify를 1 : 1로 대체 할 수 없습니다.
그러나이 질문 은 json_util.dumps ()를 사용하여 생성하고, json.loads ()를 사용하여 dict로 다시 변환하고 마지막으로 Flask의 jsonify를 호출 할 수 있음을 보여줍니다.
예 (이전 질문의 답변에서 파생 됨) :
from bson import json_util, ObjectId
import json
#Lets create some dummy document to prove it will work
page = {'foo': ObjectId(), 'bar': [ObjectId(), ObjectId()]}
#Dump loaded BSON to valid JSON string and reload it as dict
page_sanitized = json.loads(json_util.dumps(page))
return page_sanitized
이 솔루션은 ObjectId 및 기타 (예 : Binary, Code 등)를 "$ oid"와 같은 이동으로 변환합니다.
JSON 출력은 다음과 가변합니다.
{
"_id": {
"$oid": "abc123"
}
}
from bson import json_util
import json
@app.route('/')
def index():
for _ in "collection_name".find():
return json.dumps(i, indent=4, default=json_util.default)
이것은 BSON을 JSON 객체로 변환하는 샘플 예제입니다. 주 시도 할 수 있습니다.
빠른 교체 {'owner': objectid}
로 {'owner': str(objectid)}
.
그러나 자신을 정의 JSONEncoder
하는 것이 더 나은 솔루션이며 요구 사항에 따라 더 나은 솔루션입니다.
이것은 최근에 오류를 수정 한 방법입니다.
@app.route('/')
def home():
docs = []
for doc in db.person.find():
doc.pop('_id')
docs.append(doc)
return jsonify(docs)
나는 내가 늦게 게시하고 있다는 것을 알고 있지만 적어도 몇 사람에게 도움이 될 것이라고 생각했습니다!
tim과 defuz (최우수 투표)가 언급 한 예제 모두 완벽하게 작동합니다. 그러나 때때로 중요한 차이가있을 수 있습니다.
- 다음 방법은 중복되고 모든 경우에 이상적이지 않을 수있는 하나의 추가 필드를 추가합니다.
Pymongo는 json_util을 제공합니다-대신 BSON 유형을 처리하는 데 사용할 수 있습니다.
출력 : { "_id": { "$ oid": "abc123"}}
- JsonEncoder 클래스가 필요한만큼 문자열 형식으로 동일한 출력을 제공하고 json.loads (output)을 추가로 사용해야합니다. 그러나 그것은
출력 : { "_id": "abc123"}
첫 번째 방법은 간단 해 보이지만 두 방법 모두 최소한의 노력 만 필요합니다.
Flask
와 함께 사용 하는 사람들에게 유용 할 것이라고 생각하므로 여기에 게시하십시오 pymongo
. 이것은 플라스크가 pymongo bson 데이터 유형을 마샬링 할 수 있도록 허용하는 나의 현재 "모범 사례"설정입니다.
mongoflask.py
from datetime import datetime, date
import isodate as iso
from bson import ObjectId
from flask.json import JSONEncoder
from werkzeug.routing import BaseConverter
class MongoJSONEncoder(JSONEncoder):
def default(self, o):
if isinstance(o, (datetime, date)):
return iso.datetime_isoformat(o)
if isinstance(o, ObjectId):
return str(o)
else:
return super().default(o)
class ObjectIdConverter(BaseConverter):
def to_python(self, value):
return ObjectId(value)
def to_url(self, value):
return str(value)
app.py
from .mongoflask import MongoJSONEncoder, ObjectIdConverter
def create_app():
app = Flask(__name__)
app.json_encoder = MongoJSONEncoder
app.url_map.converters['objectid'] = ObjectIdConverter
# Client sends their string, we interpret it as an ObjectId
@app.route('/users/<objectid:user_id>')
def show_user(user_id):
# setup not shown, pretend this gets us a pymongo db object
db = get_db()
# user_id is a bson.ObjectId ready to use with pymongo!
result = db.users.find_one({'_id': user_id})
# And jsonify returns normal looking json!
# {"_id": "5b6b6959828619572d48a9da",
# "name": "Will",
# "birthday": "1990-03-17T00:00:00Z"}
return jsonify(result)
return app
BSON 또는 mongod 확장 JSON 을 제공하는 대신 왜 이렇게합니까 ?
mongo 특수 JSON을 제공하면 클라이언트 애플리케이션에 부담이된다고 생각합니다. 대부분의 클라이언트 앱은 복잡한 방식으로 mongo 객체를 사용하는 데 관심이 없습니다. 확장 json을 제공하면 이제 서버 측과 클라이언트 측을 사용해야합니다. ObjectId
그리고 Timestamp
문자열로 작업하기가 더 쉽고 이것은 모든 몽고 마샬링 광기를 서버에 격리시킵니다.
{
"_id": "5b6b6959828619572d48a9da",
"created_at": "2018-08-08T22:06:17Z"
}
나는 이것이 대부분의 응용 프로그램 에서 작업하는 것이 덜 번거 롭다고 생각합니다 .
{
"_id": {"$oid": "5b6b6959828619572d48a9da"},
"created_at": {"$date": 1533837843000}
}
Flask의 jsonify는 JSON Security에 설명 된대로 보안 강화를 제공합니다 . 사용자 지정 인코더가 Flask와 함께 사용되는 경우 JSON 보안 에서 논의 된 사항을 고려하는 것이 좋습니다.
은 "하지 JSON의 직렬화"오류가 발생 대부분의 사용자는 단순히 지정해야합니다 default=str
사용하는 경우 json.dumps
. 예를 들면 :
json.dumps(my_obj, default=str)
이렇게하면로 변환 str
하여 오류를 방지 할 수 있습니다. 물론 생성 된 출력을보고 그것이 필요한 것인지 확인하십시오.
레코드의 _id가 필요하지 않은 경우 DB를 쿼리 할 때 설정을 해제하는 것이 좋습니다. 이렇게하면 반환 된 레코드를 직접 인쇄 할 수 있습니다.
쿼리 할 때 _id를 설정 해제 한 다음 루프에서 데이터를 인쇄하려면 다음과 같이 작성합니다.
records = mycollection.find(query, {'_id': 0}) #second argument {'_id':0} unsets the id from the query
for record in records:
print(record)
솔루션 : mongoengine + marshmallow
당신이 사용하는 경우 mongoengine
와 marshamallow
다음이 솔루션은 적용 할 수 있습니다.
기본적으로 String
마시멜로에서 필드를 가져 왔고 인코딩 Schema id
을 위해 기본값 을 덮어 String
썼습니다.
from marshmallow import Schema
from marshmallow.fields import String
class FrontendUserSchema(Schema):
id = String()
class Meta:
fields = ("id", "email")
제 경우에는 다음과 같은 것이 필요했습니다.
class JsonEncoder():
def encode(self, o):
if '_id' in o:
o['_id'] = str(o['_id'])
return o
수용된 답변을 개선하는 추가 솔루션을 제공하고 싶습니다. 이전에 여기 에 다른 스레드 에서 답변을 제공했습니다 .
from flask import Flask
from flask.json import JSONEncoder
from bson import json_util
from . import resources
# define a custom encoder point to the json_util provided by pymongo (or its dependency bson)
class CustomJSONEncoder(JSONEncoder):
def default(self, obj): return json_util.default(obj)
application = Flask(__name__)
application.json_encoder = CustomJSONEncoder
if __name__ == "__main__":
application.run()
참고 URL : https://stackoverflow.com/questions/16586180/typeerror-objectid-is-not-json-serializable
'IT' 카테고리의 다른 글
CSS를 사용하여 모든 요소에 너비를 제공하는 방법은 무엇입니까? (0) | 2020.09.04 |
---|---|
osx mavericks에 "gem install therubyracer -v '0.10.2'"가 설치되지 않았습니다. (0) | 2020.09.04 |
jQuery를 사용하여 마우스 포커스를 설정하고 커서를 입력 끝으로 이동 (0) | 2020.09.04 |
데이터 리더에서 데이터 테이블 채우기 (0) | 2020.09.04 |
한 줄에있는 단어 사이에 둘 이상의 공백이있는 항목을 검색하는 방법 (0) | 2020.09.03 |