Meine Antwort von MongoDB nach Abfrage einer aggregierten Funktion für ein Dokument mit Python. Es gibt eine gültige Antwort zurück und ich kann sie drucken, aber nicht zurückgeben.
Error:
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
Drucken:
{'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}
Aber wenn ich versuche zurückzukehren:
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
Es ist RESTfull Aufruf:
@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 ist gut verbunden und die Sammlung ist auch da und ich habe ein gültiges erwartetes Ergebnis zurückbekommen, aber wenn ich versuche, es zurückzugeben, gibt es mir einen Json-Fehler. Jede Idee, wie die Antwort wieder in JSON konvertiert werden kann. Vielen Dank
if isinstance(o, ObjectId): return str(o)
vorherreturn
in der Methode hinzufügendefault
.from bson import ObjectId
, damit jeder noch schneller kopieren und einfügen kann? Vielen Dank!str
? Was ist falsch an diesem Ansatz?Pymongo bietet json_util - Sie können dieses stattdessen verwenden, um BSON-Typen zu verarbeiten
quelle
from bson import json_util
json.loads(json_util.dumps(user_collection))
^ Dies funktionierte nach der Installation von Python-Bsonjs mitpipenv install python-bsonjs
Aktuelles Beispiel von json_util .
Im Gegensatz zu Flask's jsonify geben "dumps" eine Zeichenfolge zurück, sodass sie nicht als 1: 1-Ersatz für Flask's jsonify verwendet werden können.
Aber diese Frage zeigt , dass wir serialisiert werden können json_util.dumps () konvertieren zurück zu DIKT mit json.loads () und rufen schließlich Flask des jsonify darauf.
Beispiel (abgeleitet aus der Antwort der vorherigen Frage):
Diese Lösung konvertiert ObjectId und andere (z. B. Binär, Code usw.) in ein Zeichenfolgenäquivalent wie "$ oid".
Die JSON-Ausgabe würde folgendermaßen aussehen:
quelle
Dies ist das Beispielbeispiel für die Konvertierung von BSON in ein JSON-Objekt. Sie können dies versuchen.
quelle
Die meisten Benutzer, die den Fehler "Nicht JSON serialisierbar" erhalten, müssen
default=str
bei der Verwendung lediglich angebenjson.dumps
. Beispielsweise:Dadurch wird eine Konvertierung erzwungen
str
, um den Fehler zu vermeiden. Schauen Sie sich dann natürlich die generierte Ausgabe an, um zu bestätigen, dass es das ist, was Sie brauchen.quelle
Als schnellen Austausch, können Sie ändern
{'owner': objectid}
zu{'owner': str(objectid)}
.Die Definition Ihrer eigenen
JSONEncoder
Lösung ist jedoch eine bessere Lösung. Sie hängt von Ihren Anforderungen ab.quelle
Hier posten, da ich denke, dass es für Leute nützlich sein kann, die
Flask
mit arbeitenpymongo
. Dies ist meine aktuelle "Best Practice" -Einstellung, um zu ermöglichen, dass der Kolben Pymongo Bson-Datentypen marshallt.mongoflask.py
app.py.
Warum tun Sie dies, anstatt BSON oder Mongod Extended JSON zu bedienen ?
Ich denke, dass das Bereitstellen von Mongo-Spezial-JSON die Clientanwendungen belastet. Die meisten Client-Apps kümmern sich nicht darum, Mongo-Objekte auf komplexe Weise zu verwenden. Wenn ich Extended JSON bediene, muss ich es jetzt serverseitig und clientseitig verwenden.
ObjectId
undTimestamp
sind einfacher als Strings zu arbeiten und dies hält all diesen Mongo-Marshalling-Wahnsinn auf dem Server unter Quarantäne.Ich denke, dass es für die meisten Anwendungen weniger lästig ist, damit zu arbeiten als.
quelle
So habe ich kürzlich den Fehler behoben
quelle
Ich weiß, dass ich zu spät poste, dachte aber, es würde zumindest ein paar Leuten helfen!
Beide Beispiele von tim und defuz (die am besten gewählt wurden) funktionieren einwandfrei. Es gibt jedoch einen winzigen Unterschied, der manchmal erheblich sein kann.
Pymongo bietet json_util - Sie können dieses stattdessen verwenden, um BSON-Typen zu verarbeiten
Ausgabe: {"_id": {"$ oid": "abc123"}}
Ausgabe: {"_id": "abc123"}
Obwohl die erste Methode einfach aussieht, erfordern beide Methoden nur einen minimalen Aufwand.
quelle
pytest-mongodb
Plugin beim Erstellen von Fixturesin meinem Fall brauchte ich so etwas:
quelle
object['_id'] = str(object['_id'])
Flask's jsonify bietet eine Sicherheitsverbesserung, wie in JSON Security beschrieben . Wenn mit Flask ein benutzerdefinierter Encoder verwendet wird, sollten Sie die in JSON Security beschriebenen Punkte berücksichtigen
quelle
Ich möchte eine zusätzliche Lösung anbieten, die die akzeptierte Antwort verbessert. Ich habe die Antworten zuvor in einem anderen Thread hier bereitgestellt .
quelle
Wenn Sie die _id der Datensätze nicht benötigen, empfehle ich, sie bei der Abfrage der Datenbank zu deaktivieren, damit Sie die zurückgegebenen Datensätze direkt drucken können, z
Um die _id beim Abfragen zu deaktivieren und dann Daten in einer Schleife zu drucken, schreiben Sie so etwas
quelle
LÖSUNG für: Mongoengine + Marshmallow
Wenn Sie
mongoengine
und verwendenmarshamallow
dann verwenden, ist diese Lösung möglicherweise für Sie anwendbar.Grundsätzlich habe ich ein
String
Feld aus Marshmallow importiert undSchema id
die zuString
codierende Standardeinstellung überschrieben .quelle
quelle
Wenn Sie keine
_id
Antwort wünschen , können Sie Ihren Code folgendermaßen umgestalten:Dadurch wird der
TypeError: ObjectId('') is not JSON serializable
Fehler behoben.quelle