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)
antesreturn
en 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_util
json.loads(json_util.dumps(user_collection))
^ esto funcionó después de instalar python-bsonjs conpipenv install python-bsonjs
Ejemplo 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=str
cuá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
JSONEncoder
es una mejor solución, depende de tus requisitos.fuente
Publicar aquí ya que creo que puede ser útil para las personas que usan
Flask
conpymongo
. 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.
ObjectId
yTimestamp
son 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-mongodb
complemento 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
mongoengine
ymarshamallow
, esta solución podría ser aplicable para usted.Básicamente, importé el
String
campo de marshmallow y sobrescribí el valor predeterminadoSchema id
paraString
codificarlo.fuente
fuente
Si no desea una
_id
respuesta, puede refactorizar su código de esta manera:Esto eliminará el
TypeError: ObjectId('') is not JSON serializable
error.fuente