Moja odpowiedź z MongoDB po zapytaniu o zagregowaną funkcję w dokumencie za pomocą Pythona, zwraca prawidłową odpowiedź i mogę ją wydrukować, ale nie mogę jej zwrócić.
Błąd:
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
Wydrukować:
{'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}
Ale kiedy próbuję wrócić:
TypeError: ObjectId('51948e86c25f4b1d1c0d303c') is not JSON serializable
To jest RESTfull call:
@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 jest dobrze połączony, a kolekcja też tam jest i wróciłem prawidłowy oczekiwany wynik, ale kiedy próbuję zwrócić, wyświetla mi się błąd Json. Każdy pomysł, jak przekonwertować odpowiedź z powrotem na JSON. Dzięki
if isinstance(o, ObjectId): return str(o)
przedreturn
metodądefault
.from bson import ObjectId
, aby każdy mógł jeszcze szybciej kopiować i wklejać? Dzięki!str
? Co jest złego w tym podejściu?Pymongo zapewnia json_util - możesz użyć tego zamiast obsługi typów BSON
źródło
from bson import json_util
json.loads(json_util.dumps(user_collection))
^ to zadziałało po zainstalowaniu python-bsonjs zpipenv install python-bsonjs
Rzeczywisty przykład z json_util .
W przeciwieństwie do jsonify Flaska, „dumps” zwróci ciąg, więc nie może być używany jako zamiennik 1: 1 jsonify Flask.
Ale to pytanie pokazuje, że możemy serializować za pomocą json_util.dumps (), przekonwertować z powrotem na dict za pomocą json.loads () i ostatecznie wywołać na nim jsonify Flaska.
Przykład (zaczerpnięty z odpowiedzi na poprzednie pytanie):
To rozwiązanie konwertuje ObjectId i inne (np. Binary, Code itp.) Na ciąg znaków równoważny, taki jak „$ oid”.
Dane wyjściowe JSON wyglądałyby następująco:
źródło
Większość użytkowników, którzy otrzymują błąd „nie można serializować JSON”, musi po prostu określić,
default=str
kiedy używajson.dumps
. Na przykład:Wymusi to konwersję na
str
, zapobiegając błędowi. Oczywiście spójrz na wygenerowane dane wyjściowe, aby potwierdzić, że jest to, czego potrzebujesz.źródło
To jest przykładowy przykład konwersji BSON do obiektu JSON. Możesz tego spróbować.
źródło
Jako szybką wymianę możesz zmienić
{'owner': objectid}
na{'owner': str(objectid)}
.Ale zdefiniowanie własnego
JSONEncoder
jest lepszym rozwiązaniem, zależy to od twoich wymagań.źródło
Publikowanie tutaj, jak myślę, może być przydatne dla osób korzystających
Flask
zpymongo
. To jest moja obecna „najlepsza praktyka” konfiguracji zezwalania kolbie na typy danych Marshall pymongo bson.mongoflask.py
app.py
Dlaczego to zamiast obsługiwać BSON lub mongod Extended JSON ?
Myślę, że obsługa mongo specjalnego JSON jest obciążeniem dla aplikacji klienckich. Większość aplikacji klienckich nie będzie przejmować się wykorzystaniem obiektów mongo w żaden złożony sposób. Jeśli obsługuję rozszerzone json, muszę teraz używać go po stronie serwera i po stronie klienta.
ObjectId
iTimestamp
są łatwiejsze w użyciu jako łańcuchy, a to sprawia, że całe to szaleństwo mongo marshalling jest poddawane kwarantannie na serwerze.Myślę, że jest to mniej uciążliwe w przypadku większości aplikacji niż.
źródło
W ten sposób ostatnio naprawiłem błąd
źródło
Wiem, że publikuję późno, ale pomyślałem, że pomoże to przynajmniej kilku osobom!
Oba przykłady wspomniane przez tima i defuz (które są najwyżej oceniane) działają doskonale. Istnieje jednak niewielka różnica, która czasami może być znacząca.
Pymongo zapewnia json_util - możesz użyć tego zamiast obsługi typów BSON
Wynik: {"_id": {"$ oid": "abc123"}}
Wynik: {"_id": "abc123"}
Mimo że pierwsza metoda wygląda na prostą, obie wymagają bardzo minimalnego wysiłku.
źródło
pytest-mongodb
wtyczki podczas tworzenia urządzeńw moim przypadku potrzebowałem czegoś takiego:
źródło
object['_id'] = str(object['_id'])
Jsonify firmy Flask zapewnia ulepszenie zabezpieczeń zgodnie z opisem w sekcji Bezpieczeństwo JSON . Jeśli niestandardowy koder jest używany z Flask, lepiej rozważyć punkty omówione w zabezpieczeniach JSON
źródło
Chciałbym przedstawić dodatkowe rozwiązanie poprawiające zaakceptowaną odpowiedź. Wcześniej podałem odpowiedzi w innym wątku tutaj .
źródło
Jeśli nie będziesz potrzebować identyfikatora _id rekordów, zalecam wyłączenie go podczas wysyłania zapytań do bazy danych, co umożliwi bezpośrednie drukowanie zwróconych rekordów, np
Aby cofnąć ustawienie _id podczas odpytywania, a następnie wypisywać dane w pętli, napisz coś takiego
źródło
ROZWIĄZANIE na: Mangusta + ptasie mleczko
Jeśli używasz
mongoengine
imarshamallow
wtedy to rozwiązanie może być stosowane dla Ciebie.Zasadniczo importowane
String
pole z prawoślazu oraz nadpisane I domyślnieSchema id
mają byćString
zakodowane.źródło
źródło
Jeśli nie chcesz
_id
w odpowiedzi, możesz refaktoryzować swój kod w następujący sposób:To usunie
TypeError: ObjectId('') is not JSON serializable
błąd.źródło