google-app-enginecomposite-keyapp-engine-ndbcompound-keyentity-groups

creating a compound or composite key on google app engine


I have two models: Car(ndb.Model) and Branch(ndb.Model) each with a key method.

@classmethod
def car_key(cls, company_name, car_registration_id):
    if not (company_name.isalnum() and car_registration_id.isalnum()):
        raise ValueError("Company & car_registration_id must be alphanumeric")
    key_name = company_name + "-" + car_registration_id
    return ndb.Key("Car", key_name)

Branch Key:

@classmethod
def branch_key(cls, company_name, branch_name):
    if not (company_name.isalnum() and branch_name.isalnum()):
        raise ValueError("Company & Branch names must be alphanumeric")
    key_name = company_name + "-" + branch_name
    return ndb.Key("Branch", key_name)

However I'm thinking this is a bit ugly and not really how you're supposed to use keys.

(the car registration is unique to a car but sometimes one company may sell a car to another company and also cars move between branches).

Since a company may many cars or many branches, I suppose I don't want large entity groups because you can only write to an entity group once per second.

How should I define my keys?

e.g. I'm considering car_key = ndb.Key("Car", car_reg_id, "Company", company_name) since it's unlikely for a car to have many companies so the entity group wont be too big.

However I'm not sure what to do about the branch key since many companies may have the same branch name, and many branches may have the same company.


Solution

  • You've rightly identified that ancestor relationships in GAE should not be based on the logical structure of your data.

    They need to be based on the transactional behavior of your application. Ancestors make your life difficult. For example, once you use a compound key, you won't be able to fetch that entity by key unless you happen to know all the elements of the key. If you knew the Car id, you wouldn't be able to fetch it without also knowing the other component.

    Consider what queries you would need to have strong consistency for. If you do happen to need strong consistency when querying all the cars in a given branch, then you should consider using that as an ancestor.

    Consider what operations need to be done in a transaction, that's another good reason for using an entity group.

    Keep in mind also, you might not need any entity group at all (probably the answer for your situation).

    Or, on the flip side, you might need an entity group that might not exactly fit any logical conceptual model, but the ancestor might be an entity that exists purely to exists because you need an ancestor for a certain transaction.