HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

One-to-many relationship with Python objects

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
objectswithonepythonmanyrelationship

Problem

I have built Python objects to simulate a one-to-many relationship and then store the object in a MongoDB instance. I am using lots of composition to achieve what I want. The code works perfectly fine but I get the feeling that the overall design can be improved a lot.

The problem statement

  • Each Portfolio can have zero or many Models.



  • Each Model can have one or many Scenarios.



  • When I create a new Model, by default one Scenario should be created and that scenario is called the baseline scenario.



The approach I used is very simple and it works for now. The output expected is a dictionary with all these entities modeled properly to store the entire document in the MongoDB instance.

```
import datetime
from bson.objectid import ObjectId
import time

from pymongo import MongoClient

# MongoDB settings for Development stage
client = MongoClient()
db = client['test']
portfolios = db['portfolios']

class PortfolioModels:
def __init__(self, model_name, parent_id):
"""
This class will be used mostly as the composition object for Portfolio class.
:param model_name: The name of the model.
:param parent_id: The portfolio id i.e self.if from the Portfolio object to keep track of the lineages.
:return: Initializes all the attributes for PortfolioModels.

For :self.id:, :self.created_date: and :self.updated_date: see the constructor of :Portfolio: class.
:self.model_scenarios: by default has the predefined attributes attached when the new PortfolioModel creates.

This is the intended behaviour because of our requirements i.e each model should have at least a single
scenario when a new model is created. It keeps track of the parent Id for proper graph lineages.
"""
self.id = str(ObjectId())
self.portfolio_id = parent_id
self.model_name = model_name
self.created_date = time.mktime(ObjectId().generation_time.timetuple()) * 1000
self.update

Solution

Don't set Portfolios._id yourself. If you insert() a dictionary without the key _id into a collection, mongodb will take care of creating an ObjectId on its own. The way you are doing it, you only store the string representation of the ObjectId and basically only have a string as your _id and lose some basic functionality.

Don't convert datetime.datetime objects to epoch timestamps to store them on fields like Portfolios.last_updated_date. pymongo automatically converts datetime.datetime objects to ISODate() and the other way around. That way you always have a human readable timestamp and easier ways to query your data.

You are composing the complete Portfolios-Object (including child-Models) first and then insert it into a collection. This seems fine and correct, but the fields PortfolioModels.id, PortfolioModels.portfolio_d, ModelScenarios.id and ModelScenarios.portfolio_model_id seem redundant, because the parent-child-relationships are already modeled by structure. This is the beauty of object-oriented databases. :)

By adding .flattened ModelScenarios to PortfolioModels and PortfolioModels to Portfolios, you mix your Models with the dict-representation of your models that get written to the mongodb. I would recommend keeping everything in your own format until just before writing to the mongo, so you are not losing the functionality of your classes.

.flatten and .expose do basicly the same thing so there is no reason to give them different names. Basically they are .to_dict(), right? It also might also be a great idea to write .from_dict() methods. So in the end you can easily transform what you get from a mongo to your models and the other way around.

Last but not least some naming advice:

  • Make your class names singular. Portfolios() creates one object which seems weird.



  • Try avoiding "code-stuttering". I guess all the code is in one module which may be in a package, so the namespace should make clear those 3 classes belong together. Ask yourself if you lose or gain readability by renaming (only a few examples, there are more of this):



  • Portfolio, PortfolioModel, ModelCenario => Portfolio, Model, Scenario



  • Portfolio.portfolio_name => Portfolio.name



  • PortfolioModel.model_name => Model.name

Context

StackExchange Code Review Q#93494, answer score: 3

Revisions (0)

No revisions yet.