개발하자

MongoDB와 관련된 FastAPI 문제 - TypeError: 'ObjectId' 개체를 인식할 수 없습니다.

Cuire 2023. 1. 15. 03:36
반응형

MongoDB와 관련된 FastAPI 문제 - TypeError: 'ObjectId' 개체를 인식할 수 없습니다.

FastAPI를 통해 MongoDB에 삽입하는 데 문제가 있습니다.

아래 코드는 예상대로 작동합니다. 변수가 에서 사용되지 않은 방법에 주목하십시오.

는 sklearn ElasticNet 모델입니다.

app = FastAPI()


def response_to_mongo(r: dict):
    client = pymongo.MongoClient("mongodb://mongo:27017")
    db = client["models"]
    model_collection = db["example-model"]
    model_collection.insert_one(r)


@app.post("/predict")
async def predict_model(features: List[float]):

    prediction = model.predict(
        pd.DataFrame(
            [features],
            columns=model.feature_names_in_,
        )
    )

    response = {"predictions": prediction.tolist()}
    response_to_mongo(
        {"predictions": prediction.tolist()},
    )
    return response

그러나 내가 이렇게 쓰고 변수를 전달할 때:

@app.post("/predict")
async def predict_model(features: List[float]):

    prediction = model.predict(
        pd.DataFrame(
            [features],
            columns=model.feature_names_in_,
        )
    )

    response = {"predictions": prediction.tolist()}
    response_to_mongo(
        response,
    )
    return response

다음과 같은 오류가 표시됩니다.

TypeError: 'ObjectId' object is not iterable

제가 읽은 바로는, 이것은 Fast 간의 BSON/JSON 문제 때문인 것 같습니다.API랑 몽고. 그런데 변수를 사용하지 않는데 첫 번째 경우에는 왜 작동하나요? 이것은 FastAPI의 비동기적 특성 때문입니까?




에 따라:

문서에 아직 키가 없는 경우 특수 키가 삽입되면 자동으로 추가됩니다. 의 값은 컬렉션 전체에서 고유해야 합니다. 의 인스턴스를 반환합니다. "_id"에 대한 자세한 내용은 를 참조하십시오.

따라서 두 번째 경우, 사전을 함수에 전달할 때, Pymongo는 데이터베이스에서 데이터를 검색하는 데 필요한 고유 식별자(즉, )를 사전에 추가합니다. 따라서 엔드포인트에서 응답을 반환할 때, 는 직렬화되지 않습니다(자세히 설명된 바와 같이, 기본적으로 FastAPI는 자동으로 실행됩니다. 를 사용하여 반환 값을 변환한 다음 a)를 반환합니다.

솔루션 1

를 기본적으로 로 변환하여 보여준 방법을 사용하면 엔드포인트 내부에서 평소와 같이 를 반환할 수 있습니다.

# place these at the top of your .py file
import pydantic
from bson import ObjectId
pydantic.json.ENCODERS_BY_TYPE[ObjectId]=str

return response # as usual

솔루션 2

로드된 문자열을 올바른 문자열로 덤프한 다음 및 설명에 따라 로 다시 로드합니다.

from bson import json_util
import json

response = json.loads(json_util.dumps(response))
return response

솔루션 3

설명에 따라 사용자 정의를 정의하여 를 다음으로 변환합니다.

import json
from bson import ObjectId

class JSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, ObjectId):
            return str(o)
        return json.JSONEncoder.default(self, o)


response = JSONEncoder().encode(response)
return response

솔루션 4

항목을 반환하기 전에 사전에서 항목을 제거합니다(에서 키를 제거하는 방법 참조).

response.pop('_id', None)
return response

반응형