从 MongoDB Atlas 获取数据时出现“ObjectId'对象不可迭代”错误[重复]

问题描述 投票:0回答:9

好吧,如果我说得不太清楚,请原谅我。每当我运行

'ObjectId' object is not iterable
函数时,我都会遇到这个
collections.find()
。浏览这里的答案,我不知道从哪里开始。我是编程新手,请耐心等待。

每次我点击应该从 Mongodb 获取数据的路线时,我都会得到

ValueError: [TypeError("'ObjectId' object is not iterable"), TypeError('vars() argument must have __dict__ attribute')]

帮助

python mongodb fastapi objectid
9个回答
10
投票

从输出中排除“_id”。

result = collection.find_one({'OpportunityID': oppid}, {'_id': 0})

8
投票

我自己也遇到了类似的问题。没有看到你的代码,我猜测回溯同样将错误跟踪到 FastAPI/Starlette 无法处理“_id”字段 - 因此你需要做的是更改结果中的“_id”字段

ObjectId 
转换为字符串类型,并在返回时将字段重命名为“id”(不带下划线),以避免出现 Pydantic 问题。


7
投票

首先,如果我们有一些您的代码示例,这会容易得多。我只能假设您没有正确地将 MongoDb 集合数据映射到 Pydantic BaseModel。

阅读MongoDB 将数据存储为 BSON。 FastAPI 将数据编码和解码为 JSON 字符串。 BSON 支持其他非 JSON 原生数据类型,包括无法直接编码为 JSON 的 ObjectId。因此,我们在将 ObjectId 存储为 _id 之前将其转换为字符串。 我想提请大家注意这个模型上的 id 字段。 MongoDB 使用 _id,但在 Python 中,属性开头的下划线具有特殊含义。如果模型上有一个以下划线开头的属性,FastAPI 使用的数据验证框架 pydantic 将假定它是私有变量,这意味着您将无法为其分配值!为了解决这个问题,我们将字段命名为 id,但给它一个别名 _id。您还需要在模型的 Config 类中将 allowed_population_by_field_name 设置为 True。

这是一个工作示例:

首先创建BaseModel:

class PyObjectId(ObjectId):
    """ Custom Type for reading MongoDB IDs """
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        if not ObjectId.is_valid(v):
            raise ValueError("Invalid object_id")
        return ObjectId(v)

    @classmethod
    def __modify_schema__(cls, field_schema):
        field_schema.update(type="string")

class Student(BaseModel):
    id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
    first_name: str
    last_name: str

    class Config:
        allow_population_by_field_name = True
        arbitrary_types_allowed = True
        json_encoders = {ObjectId: str}

现在打开所有东西:

async def get_student(student_id) -> Student:
    data = await collection.find_one({'_id': student_id})
    if data is None:
        raise HTTPException(status_code=404, detail='Student not found.')
    student: Student = Student(**data)
    return student

2
投票

在应用程序装饰器中使用响应模型这是示例示例

from pydantic import BaseModel
 class Todo(BaseModel):
   title:str
   details:str

主.py

@app.get("/{title}",response_model=Todo)
  async def get_todo(title:str):
  response=await fetch_one_todo(title)
  if not response:
    raise 
         HTTPException(status_code=status.HTTP_404_NOT_FOUND,detail='not found')
  return response

1
投票

使用 db.collection.find(ObjectId:"12348901384918")
这里 db.collection 是数据库名称,字符串使用双引号。


1
投票

我试图迭代所有文档,对我有用的是这个解决方案https://github.com/tiangolo/fastapi/issues/1515#issuecomment-782835977

这些行只需添加到 ObjectID 类的子类之后。以下链接给出了一个示例。 https://github.com/tiangolo/fastapi/issues/1515#issuecomment-782838556


0
投票

我遇到了这个问题,直到我从 mongodb 版本 5.0.9 升级到版本 6.0.0,所以 mongodb 在其末端做了一些更改来处理这个问题(如果您有能力升级的话)! 我在创建测试服务器时遇到了这个问题,当我创建一个 6.0.0 的新测试服务器时,它修复了该错误。


0
投票

好吧,所以将其添加到最上面的答案中,因为您可以在 pymongo insert 函数中运行,从而更新 python 本身内的响应字典以包含“_id”,即使它是作为参数传递的。只是新开发者可能不知道的事情。

from pymongo import *
a = {'key1':'value1'}
db1.collection1.insert(a)
print a
{'_id': ObjectId('53ad61aa06998f07cee687c3'), 'key1': 'value1'}

相关问题: 为什么在使用 pymongo 时 db.insert(dict) 将 _id 键添加到 dict 对象

文档:https://pymongo.readthedocs.io/en/stable/tutorial.html#inserting-a-document


0
投票

我对编程有点陌生(在回答这个问题时已经有一年的经验了),但到目前为止我已经与 Mongo 合作过几次了。

我提出这个问题是因为我遇到了类似的问题:我需要收集文档的 ID,但是当尝试为 $oid 下标时,会弹出错误。

最简单的答案是:如果你只有 Mongo 在 _id 对象中自动设置的 ObjectId,将整个 _id 对象转换为字符串,你就会得到 ID。 至于说:

  def get_ids(self) -> list:
    response = []
      results = self.db.collection.find()
      for x in results:
        id = str(x["_id"])
        response.append(id)
    return parse_json(response)

这样您就不会从 ObjectId 中收到错误。

© www.soinside.com 2019 - 2024. All rights reserved.