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
数据库连接良好,收集也在那里,我得到了有效的预期结果,但是当我尝试返回它给我Json错误。 任何想法如何将响应转换回JOSON。 谢谢
你应该定义你自己的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 – 你可以用它来处理BSONtypes
>>> 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”将返回一个string,所以它不能用作Flask的jsonify的1:1replace。
但是这个问题表明,我们可以使用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
这个解决scheme将ObjectId和其他(即二进制,代码等)转换为一个等价的string,如“$ oid”。
JSON输出如下所示:
{ "_id": { "$oid": "abc123" } }
作为快速replace,您可以将{'owner': objectid}
更改为{'owner': str(objectid)}
。
但是定义你自己的JSONEncoder
是一个更好的解决scheme,这取决于你的需求。
from bson import BSON 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对象的示例。 你可以试试这个
Flask的jsonify提供了安全性增强,如JSON安全中所述 。 如果自定义编码器与Flask一起使用,最好考虑JSON安全中讨论的要点
这是我最近修复错误的方法
@app.route('/') def home(): docs = [] for doc in db.person.find(): doc.pop('_id') docs.append(doc) return jsonify(docs)
我知道我迟到了,但认为这将有助于至less几个人!
tim和defuz(顶级投票)提到的例子都非常好。 然而,有时候会有很大的差别,这可能是很重要的。
- 下面的方法增加了一个多余的字段,可能在所有情况下都不是很理想
Pymongo提供了json_util – 你可以用它来处理BSONtypes
输出:{“_id”:{“$ oid”:“abc123”}}
- 由于JsonEncoder类以string格式提供相同的输出,因此我们需要另外使用json.loads(输出)。 但它导致
输出:{“_id”:“abc123”}
尽pipe第一种方法看起来很简单,但这两种方法都需要很less的努力。