Создание множественного вложенного словаря с использованием python

#python #mongodb #dictionary #nested

Вопрос:

Я изо всех сил пытаюсь создать вложенный словарь, который я буду использовать для добавления в свою коллекцию в mongodb. Я ставлю под сомнение подход и мою попытку найти решение.

Вот в чем проблема: я создал функцию, которая определяет разницу между данными локального сбора и обновлениями, которые я получаю из своего золотого источника.

Функция создает словарь всех дельт. Словарь содержит тег в качестве ключа и новое дельта-обновление в качестве значения.

Затем я передаю дельта-словарь и словарь текущих данных другой функции, которая отвечает за выполнение следующих действий:

  1. определение старого значения и нового значения с помощью дельта.ключа()
  2. создание нового словаря, который должен содержать полный путь к вложенному словарю, который будет содержать только два значения: newValue и oldValue.

С чем я борюсь, так это с тем, что, когда я делаю четыре цикла, кажется, что они просто перезаписывают предыдущую запись. Данные должны быть добавлены. Если путь существует, то при обновлении следует добавлять только дельту. Если значение еще не существует, я могу понять обновление. Например:

  1. Та же дата -> Разные теги: следует добавить новый тег, и это старое значение и новое значение.
  2. Та же дата -> Тот же тег: Следует обновить существующий тег

Причина, по которой я пытаюсь сделать это таким образом, заключается в том, что я могу избежать нескольких звонков и обновлений коллекции. В идеале придерживайтесь одного обновления.

Но меня беспокоит следующее:

  1. Является ли это лучшим подходом при работе с вложенными словарями и MongoDB ?
  2. Какие проблемы это вызовет, когда я перейду к обновлению mongodb с помощью «pymongo». Я беспокоюсь, что это затронет существующие записи в обновлении. Я хочу, чтобы записи были добавлены, а не перезаписаны.
  3. Есть ли другой подход, который имел бы больше смысла?

Это моя первая попытка 1:

 def update_record(_collection, _key, _data, _delta):
    today = date.today()
    today_formatted = today.strftime("%Y-%m-%d")
    _query_criteria = {_key: _data[_key]}
    _update_values = {}
    _append_delta = {}

    x = 0
    for delta_key in _delta.keys():
        _update_values = {delta_key: _delta[delta_key]}
            _append_delta["delta"]["byType"][delta_key][today_formatted] = {"oldValue": _data[delta_key],
                                                                            "newValue": _delta[delta_key]}
            _append_delta["delta"]["byDate"][today_formatted][delta_key] = {"oldValue": _data[delta_key],
                                                                            "newValue": _delta[delta_key]}
 

Попытка 2:

 def update_record(_collection, _key, _data, _delta):
    today = date.today()
    today_formatted = today.strftime("%Y-%m-%d")
    _query_criteria = {_key: _data[_key]}
    _update_values = {}
    _append_delta = {}

    x = 0
    for delta_key in _delta.keys():
        _update_values = {delta_key: _delta[delta_key]}
        x_dict = {}
        y_dict = {}

        if x == 0:
            _append_delta["delta"]["byType"] = {delta_key: {today_formatted: {}}}
            _append_delta["delta"]["byDate"][today_formatted] = {delta_key: {}}
            x  = 1
            _append_delta["delta"]["byType"][delta_key][today_formatted] = {"oldValue": _data[delta_key],
                                                                            "newValue": _delta[delta_key]}
            _append_delta["delta"]["byDate"][today_formatted][delta_key] = {"oldValue": _data[delta_key],
                                                                            "newValue": _delta[delta_key]}

        else:
            _append_delta.update(
                {"delta":
                    {"byType": {
                        delta_key: {today_formatted: {"oldValue": _data[delta_key], "newValue": _delta[delta_key]}}},
                        "byDate": {
                            today_formatted: {delta_key: {"oldValue": _data[delta_key], "newValue": _delta[delta_key]}}}
                    }
                }
            )
 

Пример того, как я хочу, чтобы коллекция выглядела в MongoDB:

 [{name: "Apple",
 ticker: "appl",
 description: "Apple Computers",
 currency: "usd",
 delta: {
     byTag: {
         name: {
             "2021-06-01": {
                 oldValue: "appl",
                 newValue: "Apple"
             }
         },
         description: {
             "2021-06-06": {
                 oldValue: "Apple",
                 newValue: "Apple Computers"
             }
         }
     },
     byDate: {
         "2021-06-01": {
             name: {
                 oldValue: "appl",
                 newValue: "Apple"
             }
         },
        "2021-06-06": {
             description: {
                 oldValue: "Apple",
                 newValue: "Apple Computers"
             }
         }

     }
 }
 }]
 

Ответ №1:

У вас здесь много вопросов. Вы можете получить лучший ответ, если разбите их на проблемы размера укуса.

С точки зрения работы с изменениями в ваших данных, вы, возможно, захотите взглянуть на диктдиффер. Как и во многих других вещах в python, обычно есть хорошая библиотека для достижения того, что вы хотите сделать. Это не даст вам формат, который вы ищете, но даст вам формат, который сообщество определило как наилучшую практику для решения такого рода проблем. Вы также получаете дополнительные замечательные вещи, например, возможность исправлять старые записи с помощью дельты.

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

 from pymongo import MongoClient
from datetime import date
from bson.json_util import dumps

db = MongoClient()['mydatabase']


class UpdateRecord:
    def __init__(self, name, ticker, description, currency, delta):
        self.name = name
        self.ticker = ticker
        self.description = description
        self.currency = currency
        self.date = date.today().strftime("%Y-%m-%d")
        self.delta = delta
        # Need to code to work out the deltas

    def by_tags(self):
        tags = dict()
        for tag in ['name', 'description']:
            tags.update({
                tag: {
                    self.date: {
                        'oldValue': "appl",
                        'newValue': "Apple"
                    }
                }
            })
        return tags

    def by_date(self):
        dates = dict()
        for dt in ['2021-06-01', '2021-06-06']:
            dates.update({
                dt: {
                    self.date: {
                        'oldValue': "appl",
                        'newValue': "Apple"
                    }
                }
            })
        return dates

    def to_dict(self):
        return {
            'name': self.name,
            'ticker': self.ticker,
            'description': self.description,
            'currency': self.currency,
            'delta': {
                'byTag': self.by_tags(),
                'byDate': self.by_date()
            }
        }

    def update(self, _id):
        db.mycollection.update_one({'_id': _id}, {'$push': {'Updates': self.to_dict()}})


delta = {
    'oldValue': "appl",
    'newValue': "Apple"
}
#
# Test it out
#
dummy_record = {'a': 1}
db.mycollection.insert_one(dummy_record)
record = db.mycollection.find_one()

update_record = UpdateRecord(name='Apple', ticker='appl', description='Apple Computer', currency='usd', delta=delta)
update_record.update(record.get('_id'))

print(dumps(db.mycollection.find_one({}, {'_id': 0}), indent=4))
 

С принтами:

 {
    "a": 1,
    "Updates": [
        {
            "name": "Apple",
            "ticker": "appl",
            "description": "Apple Computer",
            "currency": "usd",
            "delta": {
                "byTag": {
                    "name": {
                        "2021-08-14": {
                            "oldValue": "appl",
                            "newValue": "Apple"
                        }
                    },
                    "description": {
                        "2021-08-14": {
                            "oldValue": "appl",
                            "newValue": "Apple"
                        }
                    }
                },
                "byDate": {
                    "2021-06-01": {
                        "2021-08-14": {
                            "oldValue": "appl",
                            "newValue": "Apple"
                        }
                    },
                    "2021-06-06": {
                        "2021-08-14": {
                            "oldValue": "appl",
                            "newValue": "Apple"
                        }
                    }
                }
            }
        }
    ]
}