App Engine: One-to-One Entity Relationships
Articles like this one tell you how to do one-to-many and many-to-many relationships, but they don't tell you the optimal way to do one-to-one relationships. You might think that you don't need one-to-one relationships because you can just stick all of your data on just one entity. The problem with that is that entity size does matter. If you are always loading an entity, but you don't frequently access all of the properties on that entity, then you are wasting memory to load that entity and are also adding to the response size.
One-to-one relationships can be useful. For example, for us we have a UserProfile entity and a UserStats entity that have a one-to-one relationship. We are always loading the UserProfile, but we rarely need any info from the UserStats entity so there was no need to bloat UserProfile with the data we are storing on UserStats.
The current obvious options (I can think of) for one-to-one are:
1) Make UserStats a child of UserProfile in an entity group. This is ok if you absolutely need transactions on the two objects. In our case we don't care about that. The other problem with this is that you would have to do an ANCESTOR query to get the UserStats object from the UserProfile object. We'd rather used a db GET instead for speed reasons. In our case we only care about going one way with the lookups and that way is from UserProfile to UserStats. We always have UserProfile first.
2) Make a reference property from UserProfile to UserStats. The problem with this method is that it puts a dependency of UserProfile on UserStats and adds more data to the UserProfile object, which we're trying to avoid. We don't want to have to worry about UserProfile ever having a bad reference property.
So, our solution was to create UserStats with the key_name of the db id of UserProfile. This lets us go easily from UserProfile to UserStats without having to have UserProfile depend on UserStats.
It works like this. Whenever we want to create a UserStats entity we use the get_or_insert method which takes in a key_name:
user_stats = UserStats.get_or_insert(str(user_profile.key().id()))
Then in our code when we have the UserProfile entity we can retrieve the UserStats entity quickly by key_name:
user_stats = UserStats.get_by_key_name(str(user_profile.key().id()))










