【问题标题】:How should I deal with '_id' in Dataclass when used in combination with MongoDB?与 MongoDB 结合使用时,我应该如何处理 Dataclass 中的“_id”?
【发布时间】:2020-07-02 19:21:23
【问题描述】:

我有一个 MongoDB,并希望将每个文档存储为一个 python 数据类的实例。我对“_id”有疑问。当我创建一个本地实例时,我不想分配一个“_id”。但是,在检索文档时,实例应该包含“_id”。

我的方法是将“_id”设置为无。当我将实例插入数据库时​​,这不起作用。 None 的值作为 '_id' 传递。

有没有办法使用数据类创建模型,允许我将本地和检索到的数据存储为同一类的实例?

from dataclasses import dataclass 
from typing import List

from bson import ObjectId

@dataclass
class Article:
    name: str
    quantity: int
    _id: ObjectId = None
    description: str = ""

插入本地实例

import dataclasses
from pymongo import MongoClient

article = Article(name="pen", description="A writing device", quantity=100)

self.client = MongoClient()
self.db = self.client.warehouse
self.collection = self.db["articles"]
res = self.collection.insert_one(dataclasses.asdict(article)) # <-- Should not contain "_id"

检索文档

res = self.collection.find_one("_id": ObjectID())
article = Article(**res) # <-- Article should contain id

【问题讨论】:

  • 不设置_id会怎样?
  • 如果我没有设置 '_id' 默认值 None 被设置并提交到数据库。
  • 这和你想要的有什么不同?
  • 我希望 MongoDB 创建一个 ObjectId。这是 Mongo 的默认行为。然后使用此唯一 ID 再次找到它。
  • 服务器中的所有文档都应该有一个_id字段,您是否成功插入了一个没有_id的文档?

标签: python mongodb python-dataclasses


【解决方案1】:
from dataclasses import dataclass, asdict
from typing import Optional


@dataclass
class Article:
    name: str
    quantity: int
    id: Optional[int] = None
    description: str = ''

    def to_short_dict(self):
        result = asdict(self)
        result.pop('id')
        return result


# not contain "id"
input_data = {
    'name': 'pen', 'quantity': 100, 'description': 'A writing device',
}
article = Article(**input_data)
assert article.to_short_dict() == input_data

# contain "id"
input_data = {
    'id': 1,
    'name': 'pen', 'quantity': 100, 'description': 'A writing device',
}
article = Article(**input_data)
assert asdict(article) == input_data

【讨论】:

  • 我喜欢这个功能的想法。我正在寻找更通用的解决方案。
【解决方案2】:

我试图想出一个更通用的解决方案:

我创建了一个接口MongoDataclass,我的所有模型都从该接口继承。该接口包含一个方法,该方法返回值不是None 的所有键值对作为字典。

在我看来,这是有道理的,因为 MongoDB 是无模式的,我不想在我的文档中存储任何 None 值。这也解决了 '_id' 的问题。

import abc
from dataclasses import dataclass

@dataclass
class MongoDataclass(abc.ABC):

    def as_json_wo_none(self):
        return {key: value for key, value in dataclasses.asdict(self).items() if value is not None}

【讨论】:

  • 1.{key: value for key, value in dataclasses.asdict(self).items() if value is not None} 2. 并且不需要从abc.ABC继承
  • 我同意你的第一点(更正了我的回答)。为什么要删除抽象基类?我希望所有与 Mongo 结合使用的数据类都继承自这个抽象基类。
  • abc.ABC 没用,因为你的类中没有抽象方法
  • 我可能有其他字段值 None 作为我可能感兴趣的值。您的解决方案不仅仅解决了_id 问题(并不总是可取的)。
猜你喜欢
  • 1970-01-01
  • 2019-12-16
  • 2012-07-19
  • 2014-03-15
  • 1970-01-01
  • 2015-01-02
  • 2015-12-28
  • 2013-09-15
  • 2011-05-29
相关资源
最近更新 更多