Minha resposta de volta do MongoDB depois de consultar uma função agregada no documento usando Python, ela retorna uma resposta válida e posso imprimi-la, mas não posso retorná-la.
Erro:
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
Impressão:
{'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}
Mas quando tento voltar:
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
É uma chamada 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
O banco de dados está bem conectado e a coleção também está lá e recebi um resultado esperado válido, mas quando tento retornar, ele me dá um erro de Json. Alguma ideia de como converter a resposta de volta em JSON. obrigado
if isinstance(o, ObjectId): return str(o)
antesreturn
no métododefault
.from bson import ObjectId
, para que todos possam copiar e colar ainda mais rápido? Obrigado!str
? O que há de errado com essa abordagem?Pymongo fornece json_util - você pode usar esse em vez de lidar com tipos BSON
fonte
from bson import json_util
json.loads(json_util.dumps(user_collection))
^ funcionou depois de instalar o python-bsonjs compipenv install python-bsonjs
Exemplo real de json_util .
Ao contrário do jsonify do Flask, "dumps" retornará uma string, portanto, não pode ser usado como uma substituição 1: 1 do jsonify do Flask.
Mas essa pergunta mostra que podemos serializar usando json_util.dumps (), converter de volta para dict usando json.loads () e finalmente chamar o jsonify do Flask nele.
Exemplo (derivado da resposta da pergunta anterior):
Esta solução irá converter ObjectId e outros (ou seja, Binário, Código, etc) em uma string equivalente, como "$ oid".
A saída JSON ficaria assim:
fonte
Este é o exemplo de amostra para converter BSON em objeto JSON. Você pode tentar isso.
fonte
A maioria dos usuários que recebe o erro "não serializável em JSON" simplesmente precisa especificar
default=str
ao usarjson.dumps
. Por exemplo:Isso forçará uma conversão para
str
, evitando o erro. Obviamente, observe a saída gerada para confirmar se é o que você precisa.fonte
Como uma substituição rápida, você pode mudar
{'owner': objectid}
para{'owner': str(objectid)}
.Mas definir o seu próprio
JSONEncoder
é uma solução melhor, depende dos seus requisitos.fonte
Postando aqui, pois acho que pode ser útil para pessoas que usam
Flask
compymongo
. Esta é minha configuração de "prática recomendada" atual para permitir que o flask marque os tipos de dados bson pymongo.mongoflask.py
app.py
Por que fazer isso em vez de servir BSON ou JSON estendido mongod ?
Acho que servir JSON especial ao mongo sobrecarrega os aplicativos clientes. A maioria dos aplicativos cliente não se importará com o uso de objetos mongo de forma complexa. Se eu servir o json estendido, agora tenho que usá-lo no lado do servidor e no lado do cliente.
ObjectId
eTimestamp
são mais fáceis de trabalhar como strings e isso mantém toda essa loucura de marshalling mongo em quarentena para o servidor.Acho que isso é menos oneroso de se trabalhar para a maioria dos aplicativos do que.
fonte
Foi assim que corrigi o erro recentemente
fonte
Sei que estou postando tarde, mas pensei que ajudaria pelo menos algumas pessoas!
Ambos os exemplos mencionados por tim e defuz (que são os mais votados) funcionam perfeitamente bem. No entanto, há uma diferença mínima que às vezes pode ser significativa.
Pymongo fornece json_util - você pode usar esse em vez de lidar com tipos BSON
Resultado: {"_id": {"$ oid": "abc123"}}
Resultado: {"_id": "abc123"}
Mesmo assim, o primeiro método parece simples, ambos os métodos precisam de um esforço mínimo.
fonte
pytest-mongodb
plugin ao criar fixturesno meu caso, eu precisava de algo assim:
fonte
object['_id'] = str(object['_id'])
O jsonify do Flask fornece aprimoramento de segurança conforme descrito em Segurança JSON . Se um codificador personalizado for usado com o Flask, é melhor considerar os pontos discutidos no JSON Security
fonte
Eu gostaria de fornecer uma solução adicional que melhora a resposta aceita. Eu já forneci as respostas em outro tópico aqui .
fonte
Se você não precisar do _id dos registros, recomendo removê-lo ao consultar o banco de dados, o que permitirá que você imprima os registros retornados diretamente, por exemplo
Para remover o _id ao consultar e depois imprimir os dados em um loop, você deve escrever algo assim
fonte
SOLUÇÃO para: mongoengine + marshmallow
Se você usar
mongoengine
e,marshamallow
então, esta solução pode ser aplicável para você.Basicamente, importei o
String
campo do marshmallow e substituí o padrãoSchema id
para serString
codificado.fonte
fonte
Se você não quiser uma
_id
resposta, pode refatorar seu código mais ou menos assim:Isso removerá o
TypeError: ObjectId('') is not JSON serializable
erro.fonte