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(顶级投票)提到的例子都非常好。 然而,有时候会有很大的差别,这可能是很重要的。

  1. 下面的方法增加了一个多余的字段,可能在所有情况下都不是很理想

Pymongo提供了json_util – 你可以用它来处理BSONtypes

输出:{“_id”:{“$ oid”:“abc123”}}

  1. 由于JsonEncoder类以string格式提供相同的输出,因此我们需要另外使用json.loads(输出)。 但它导致

输出:{“_id”:“abc123”}

尽pipe第一种方法看起来很简单,但这两种方法都需要很less的努力。