umon go, pymon go, python 3, как мне загрузить данные из опорных полей - PullRequest
0 голосов
/ 18 апреля 2020

Я пытаюсь понять, как и почему так сложно загрузить мои ссылочные данные в unmongo / pymon go

@instance.register
class MyEntity(Document):
    account = fields.ReferenceField('Account', required=True)
    date = fields.DateTimeField(
        default=lambda: datetime.utcnow(),
        allow_none=False
    )
    positions = fields.ListField(fields.ReferenceField('Position'))
    targets = fields.ListField(fields.ReferenceField('Target'))

    class Meta:
        collection = db.myentity

, когда я получаю это с помощью:

    def find_all(self):
        items = self._repo.find_all(
            {
                'user_id': self._user_id
            }
        )
        return items

, а затем выгрузите его так:

    from bson.json_util import dumps

    all_items = []
    for item in all_items:
        all_items.append(item.dump())


    return dumps(all_items)

я получаю следующий JSON объект:

[
  {
    "account": "5e990db75f22b6b45d3ce814",
    "positions": [
      "5e9a594373e07613b358bdbb",
      "5e9a594373e07613b358bdbe",
      "5e9a594373e07613b358bdc1"
    ],
    "date": "2020-04-18T01:34:59.919000+00:00",
    "id": "5e9a594373e07613b358bdcb",
    "targets": [
      "5e9a594373e07613b358bdc4",
      "5e9a594373e07613b358bdc7",
      "5e9a594373e07613b358bdca"
    ]
  }
]

и без dump

<object Document models.myentity.schema.MyEntity({
'targets':
    <object umongo.data_objects.List([
        <object umongo.frameworks.pymongo.PyMongoReference(
            document=Target,
            pk=ObjectId('5e9a594373e07613b358bdc4')
            )>,
        <object umongo.frameworks.pymongo.PyMongoReference(
            document=Target,
            pk=ObjectId('5e9a594373e07613b358bdc7')
            )>,
        <object umongo.frameworks.pymongo.PyMongoReference(
            document=Target,
            pk=ObjectId('5e9a594373e07613b358bdca'))>]
            )>,
            'id': ObjectId('5e9a594373e07613b358bdcb'),
'positions':
    <object umongo.data_objects.List([
        <object umongo.frameworks.pymongo.PyMongoReference(
            document=Position,
            pk=ObjectId('5e9a594373e07613b358bdbb')
        )>,
        <object umongo.frameworks.pymongo.PyMongoReference(
            document=Position,
            pk=ObjectId('5e9a594373e07613b358bdbe'))>,
        <object umongo.frameworks.pymongo.PyMongoReference(
            document=Position,
            pk=ObjectId('5e9a594373e07613b358bdc1'))>])>,
'date': datetime.datetime(2020, 4, 18, 1, 34, 59, 919000),
'account': <object umongo.frameworks.pymongo.PyMongoReference(document=Account, pk=ObjectId('5e990db75f22b6b45d3ce814'))>
})>
  1. Я действительно борюсь за то, чтобы разыменовать это. Я хотел бы, чтобы рекурсивно, что все загруженные поля, если я укажу их в схеме umon go, разыменовываются. Разве это не в API Umon go?

т.е. что, если в 'target' также есть поле ссылки? Я понимаю, что это может быть дорого на БД, но есть ли способ указать это в самом определении схемы? то есть в мета-классе, что я всегда хочу полный, разыменованный объект для определенного поля?

тот факт, что я нахожу очень мало документации / комментариев по этому поводу, что это даже не упомянуто в документах umon go, а некоторые решения для других ODM, которые я нашел (например, mongoengine), мучительно пишут рекурсивно , ручные функции на поле / на запрос. Это наводит на мысль, что есть причина, по которой этот вопрос не является популярным. Может быть анти-шаблон? если так, то почему?

Я не новичок в mon go, но новичок в python / mon go. Я чувствую, что мне здесь чего-то не хватает.


РЕДАКТИРОВАТЬ: так сразу после публикации, я нашел эту проблему:

https://github.com/Scille/umongo/issues/42

, которая обеспечивает путь вперед

это все еще лучший подход? Все еще пытаюсь понять, почему это рассматривается как крайний случай.


РЕДАКТИРОВАТЬ 2: прогресс

class MyEntity(Document):
    account = fields.ReferenceField('Account', required=True, dump=lambda: 'fetch_account')
    date = fields.DateTimeField(
        default=lambda: datetime.utcnow(),
        allow_none=False
    )
    #trade = fields.DictField()
    positions = fields.ListField(fields.ReferenceField('Position'))
    targets = fields.ListField(fields.ReferenceField('Target'))

    class Meta:
        collection = db.trade

    @property
    def fetch_account(self):
        return self.account.fetch()

, поэтому с вновь определенным декоратором свойств я могу сделать:

    items = MyEntityService().find_all()
    allItems = []
    for item in allItems:
        account = item.fetch_account
        log(account.dump())
        allItems.append(item.dump())

Когда я сбрасываю учетную запись, все хорошо. Но я не хочу явно / вручную делать это. Это по-прежнему означает, что я должен рекурсивно распаковывать, а затем перепаковывать каждую ссылку do c и любые дочерние ссылки каждый раз, когда я делаю запрос. Это также означает, что SOT-схема больше не содержится только в классе umon go, т. Е. Если поле изменяется, мне придется проводить рефакторинг каждого запроса, использующего это поле.

Я все еще ищу способ украсить / пометить это на самой схеме. например,

    account = fields.ReferenceField('Account', required=True, dump=lambda: 'fetch_account')

dump=lambda: 'fetch_account' Я только что придумал, он ничего не делает, но это более или менее шаблон, к которому я иду, не уверенный, возможно ли это (или даже умный: другое направление, указатели на то, почему я полностью неправ в моем подходе, приветствуются) ....


РЕДАКТИРОВАТЬ 3: так вот, где я приземлился:

    @property
    def fetch_account(self):
        return self.account.fetch().dump()

    @property
    def fetch_targets(self):
        targets_list = []
        for target in self.targets:
            doc = target.fetch().dump()
            targets_list.append(doc)
        return targets_list

    @property
    def fetch_positions(self):
        positions_list = []
        for position in self.positions:
            doc = position.fetch().dump()
            positions_list.append(doc)
        return positions_list

и затем получить доступ к:

    allItems = []
    for item in items:
        account = item.fetch_account
        positions = item.fetch_positions
        targets = item.fetch_targets

        item = item.dump()
        item['account'] = account
        item['positions'] = positions
        item['targets'] = targets
        # del item['targets']
        allTrades.append(item)

Я мог бы это почистить / немного абстрагировать, но я не понимаю, как я мог бы реально уменьшить общее многословие на данный момент. Это, кажется, дает мне результат, который я ищу, хотя:

[
  {
    "date": "2020-04-18T01:34:59.919000+00:00",
    "targets": [
      {
        "con_id": 331641614,
        "value": 106,
        "date": "2020-04-18T01:34:59.834000+00:00",
        "account": "5e990db75f22b6b45d3ce814",
        "id": "5e9a594373e07613b358bdc4"
      },
      {
        "con_id": 303019419,
        "value": 0,
        "date": "2020-04-18T01:34:59.867000+00:00",
        "account": "5e990db75f22b6b45d3ce814",
        "id": "5e9a594373e07613b358bdc7"
      },
      {
        "con_id": 15547841,
        "value": 9,
        "date": "2020-04-18T01:34:59.912000+00:00",
        "account": "5e990db75f22b6b45d3ce814",
        "id": "5e9a594373e07613b358bdca"
      }
    ],
    "account": {
      "user_name": "hello",
      "account_type": "LIVE",
      "id": "5e990db75f22b6b45d3ce814",
      "user_id": "U3621607"
    },
    "positions": [
      {
        "con_id": 331641614,
        "value": 104,
        "date": "2020-04-18T01:34:59.728000+00:00",
        "account": "5e990db75f22b6b45d3ce814",
        "id": "5e9a594373e07613b358bdbb"
      },
      {
        "con_id": 303019419,
        "value": 0,
        "date": "2020-04-18T01:34:59.764000+00:00",
        "account": "5e990db75f22b6b45d3ce814",
        "id": "5e9a594373e07613b358bdbe"
      },
      {
        "con_id": 15547841,
        "value": 8,
        "date": "2020-04-18T01:34:59.797000+00:00",
        "account": "5e990db75f22b6b45d3ce814",
        "id": "5e9a594373e07613b358bdc1"
      }
    ],
    "id": "5e9a594373e07613b35
8bdcb"
  }
]

1 Ответ

1 голос
/ 18 апреля 2020

Кажется, что это выбор дизайна в umon go.

Например, в Mongoid (ODM Ruby для MongoDB), когда на объект ссылаются, он выбирается из базы данных автоматически через ассоциации по мере необходимости.

Кроме того, в ODM функции "определить структуру поля" и "беспрепятственный доступ к данным через объекты приложения" совершенно разные. Например, мой опыт работы с Hibernate в Java показывает, что он похож на то, что вы обнаруживаете с помощью umon go - после загрузки данных он обеспечивает способ доступа к данным с использованием определенной в приложении структуры полей с типами et c., Но это не очень помогает с прозрачной загрузкой данных из домена приложения.

...