Mi respuesta de MongoDB después de consultar una función agregada en un documento usando Python, devuelve una respuesta válida y puedo imprimirla pero no puedo devolverla.
Error:
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
Impresión:
{'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}
Pero cuando trato de regresar:
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
Es llamada 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 está bien conectado y la colección también está allí y obtuve un resultado esperado válido, pero cuando intento devolverlo, me da un error de Json. Cualquier idea de cómo volver a convertir la respuesta en JSON. Gracias

if isinstance(o, ObjectId): return str(o)antesreturnen el métododefault.from bson import ObjectId, para que todos puedan copiar y pegar aún más rápido? ¡Gracias!str? ¿Qué hay de malo en ese enfoque?Pymongo proporciona json_util ; puede usar ese en su lugar para manejar tipos BSON
fuente
from bson import json_utiljson.loads(json_util.dumps(user_collection))^ esto funcionó después de instalar python-bsonjs conpipenv install python-bsonjsEjemplo real de json_util .
A diferencia de jsonify de Flask, los "volcados" devolverán una cadena, por lo que no se puede usar como un reemplazo 1: 1 de jsonify de Flask.
Pero esta pregunta muestra que podemos serializar usando json_util.dumps (), volver a convertir a dict usando json.loads () y finalmente llamar a jsonify de Flask en él.
Ejemplo (derivado de la respuesta de la pregunta anterior):
Esta solución convertirá ObjectId y otros (es decir, binario, código, etc.) en una cadena equivalente como "$ oid".
La salida JSON se vería así:
fuente
Este es el ejemplo de muestra para convertir BSON en un objeto JSON. Puedes probar esto.
fuente
La mayoría de los usuarios que reciben el error "no serializable JSON" simplemente necesitan especificar
default=strcuándo usarjson.dumps. Por ejemplo:Esto forzará una conversión a
str, evitando el error. Por supuesto, luego mire la salida generada para confirmar que es lo que necesita.fuente
Como reemplazo rápido, puede cambiar
{'owner': objectid}a{'owner': str(objectid)}.Pero definir el tuyo propio
JSONEncoderes una mejor solución, depende de tus requisitos.fuente
Publicar aquí ya que creo que puede ser útil para las personas que usan
Flaskconpymongo. Esta es mi configuración actual de "mejores prácticas" para permitir que flask marshall pymongo bson tipos de datos.mongoflask.py
app.py
¿Por qué hacer esto en lugar de servir BSON o JSON extendido mongod ?
Creo que servir JSON especial de mongo supone una carga para las aplicaciones cliente. A la mayoría de las aplicaciones cliente no les importará el uso de objetos mongo de forma compleja. Si sirvo json extendido, ahora tengo que usarlo del lado del servidor y del lado del cliente.
ObjectIdyTimestampson más fáciles de trabajar como cadenas y esto mantiene toda esta locura de clasificación de mongo en cuarentena en el servidor.Creo que trabajar con esto es menos oneroso para la mayoría de las aplicaciones que.
fuente
Así es como recientemente solucioné el error
fuente
¡Sé que publico tarde, pero pensé que ayudaría al menos a algunas personas!
Tanto los ejemplos mencionados por tim como defuz (que son los más votados) funcionan perfectamente bien. Sin embargo, existe una pequeña diferencia que a veces puede ser significativa.
Pymongo proporciona json_util; puede usar ese en su lugar para manejar tipos BSON
Salida: {"_id": {"$ oid": "abc123"}}
Salida: {"_id": "abc123"}
Aunque el primer método parece simple, ambos métodos requieren un esfuerzo mínimo.
fuente
pytest-mongodbcomplemento al crear accesoriosen mi caso necesitaba algo como esto:
fuente
object['_id'] = str(object['_id'])Jsonify de Flask proporciona una mejora de seguridad como se describe en Seguridad JSON . Si se usa un codificador personalizado con Flask, es mejor considerar los puntos discutidos en Seguridad JSON
fuente
Me gustaría proporcionar una solución adicional que mejore la respuesta aceptada. Anteriormente he proporcionado las respuestas en otro hilo aquí .
fuente
Si no va a necesitar el _id de los registros, recomendaré desarmarlo cuando consulte la base de datos, lo que le permitirá imprimir los registros devueltos directamente, por ejemplo.
Para desarmar el _id al consultar y luego imprimir datos en un bucle, escribe algo como esto
fuente
SOLUCIÓN para: mongoengine + marshmallow
Si usa
mongoengineymarshamallow, esta solución podría ser aplicable para usted.Básicamente, importé el
Stringcampo de marshmallow y sobrescribí el valor predeterminadoSchema idparaStringcodificarlo.fuente
fuente
Si no desea una
_idrespuesta, puede refactorizar su código de esta manera:Esto eliminará el
TypeError: ObjectId('') is not JSON serializableerror.fuente