1

在 pymongo 中是否可以让该collection.find()方法返回一个从基类继承的自定义游标类,但重新定义迭代的发生方式?

我想在迭代时从光标内的 mongo 数据实例化应用程序特定模型。文档有一个type属性,它将确定应该创建什么样的实例。我在想该next方法可以查看这些数据并决定创建和返回哪种类型。从光标继承很容易,但我不知道在哪里将它挂钩到find()操作中?

编辑或者...

我目前正在做的是用来yield吐出一个生成器,该生成器将在执行获取之后对对象进行分类。

@classmethod
def gather(cls,place_id):
    """
    Gather instances of all the shouts for one place
    """
    shouts = cls.collection.find({'place_id':place_id})
    for s in shouts:
        yield Shout.classify(s)

@classmethod
def classify(cls,shout):
    if shout.type == 1:
        return Type1(dict(shout))
    elif shout.type == 2:
        return Type2(dict(shout))
    elif shout.type == 3:
        return Type3(dict(shout))

问题是这并没有保留封装在默认 pymongo 中的括号键访问的原始方法Cursor

如果我要创建一个仅接受游标实例并包装其方法的包装类,我需要重写哪些魔术方法以保留原始游标的迭代行为?我在想这样的事情:

class StuffCursor():

    cursor = False

    def __init__(self,cursor):
        self.cursor = cursor

    def __getattr__(self,attr):
        #This passes off most key-based calls, like bracket-access, to the cursor
        return getattr(self.cursor,attr)

这正是我能想到的,但是任何可以在迭代器之上堆叠一些额外处理,然后返回修改后的迭代器的东西都可以。

4

2 回答 2

1

讨厌回答我自己的问题,但这可能对任何使用谷歌搜索的人都有用。这是我最终的结果:

class ShoutCursor():
    """
    Custom cursor class that will instantiate shout models
    at query time.
    """

    cursor = False

    def __init__(self,cursor):
        self.cursor = cursor
        self.cursor.sort('created',DESCENDING)

    def __iter__(self):
        for ent in self.cursor:
            yield Shout.classify(ent)

    def __len__(self):
        return self.cursor.count()

    def __getitem__(self,index):
        try:
            ents = itertools.islice(self.cursor,index,index+1)
            return [Shout.classify(ent) for ent in ents][0]
        except TypeError:
            return list(Shout.classify(ent) for ent in itertools.islice(self.cursor,index.start,index.stop,index.step))

    def sort(*args,**kwargs):
        self.cursor.sort(*args,**kwargs)

    def __getattr__(self,attr):
        return getattr(self.cursor,attr)

__iter__和方法是将__getiem__修改后的实例化模型加载到生成器中返回的地方。其他方法保留本机光标操作。将游标传入__init__设置功能,如此特殊,每次迭代逻辑都可以在从 mongo 获取对象时执行。

于 2012-10-11T19:10:52.037 回答
0

我不知道是否可以使用“猴子补丁”来实现这一点,但我最终做到了,如下所示。这允许我在Cursor类上添加/覆盖函数。

from pymongo import MongoClient
from pymongo.collection import Collection
from pymongo.cursor import Cursor
from pymongo.database import Database

class CustomCursor(Cursor):
    # Customize Cursor here, either by overriding or extending with more methods


class CustomCollection(Collection):
    def __init__(self, database: Database, name: str) -> None:
        super().__init__(database, name)

    # find_one seems to use find, but you may need to override in more places.
    def find(self, *args, **kwargs):
        return CustomCursor(self, *args, **kwargs)


class CustomDatabase(Database):
    def __init__(self, client: MongoClient, name: str) -> None:
        super().__init__(client, name)

    def __getitem__(self, name: str) -> CustomCollection:
        return CustomCollection(self, name)

# usage:
client = MongoClient('127.0.0.1', 27017)
database = CustomDatabase(client, 'mydb')

我用and方法定义了一个Serializable基类。这使我可以定义 a以便我可以查询并取回类实例:from_dictto_dictto_list()CustomCursor

result: List[School] = database.schools.find().to_list(School)
于 2021-05-12T12:55:39.533 回答