复杂,昂贵的多对多实体引用

时间:2016-02-05 16:22:48

标签: google-app-engine database-design google-cloud-datastore data-modeling app-engine-ndb

我有四种主要类型:帐户,公司,服务和地址。我希望在公司和服务实体之间共享地址实体。

  • 帐户:这是用户帐户(电子邮件,密码)
  • 公司:提供服务的业务(祖先:账户)
  • 服务:公司(祖先:公司)提供的服务
  • 地址:公司或服务(祖先:帐户)的地址(字段组:街道,城市,国家)

挑战: 公司和服务实体可能具有不同的地址;毕竟,公司的地址不一定是获得服务的地方。服务可能有许多地址,因为公司可能会设立不同的特许经营/出口,可以获得其服务。

我想以这样的方式对数据建模,即公司或服务实体或两者都可以引用地址。我尝试了这两种方法:

我们假设这是地址模型:

class Address(ndb.Model):
    street = ndb.StringProperty(required=True)
    city = ndb.StringProperty(required=True)
    country = ndb.StringProperty(required=True)

方法1 :存储服务或公司内的地址密钥列表

class Service(ndb.Model):
    title = ndb.StringProperty(required=True)
    addresses = ndb.KeyProperty(repeated=True)

class Company(ndb.Model):
    name = ndb.StringProperty(required=True)
    addresses = ndb.KeyProperty(repeated=True)

问题:对于服务或公司的每个页面视图,我需要执行其他查询以获取其各自的地址。随着我们的实体数量的增长,这会成为一个非常昂贵的问题。

方法2 :创建一个AddressMapping实体,形成两个实体之间的关系:

class Service(ndb.Model):
    title = ndb.StringProperty(required=True)
    addresses = ndb.KeyProperty(repeated=True)

class AddressMapping(ndb.Model):
    entity = ndb.StringProperty(required=True)  # service or company
    address = ndb.KeyProperty(repeated=True)

问题:如果服务被禁用/删除/修改,我们需要删除/修改所有附带的AddressMapping实体,否则它们将被孤立。查看页面时仍需要其他查询。这看起来也很昂贵。

这是我提出的两种方法;他们都看起来很糟糕。关于如何改进这个的任何想法?

2 个答案:

答案 0 :(得分:1)

如果您在公司和服务模型中存储地址密钥,则不需要“其他查询来获取它们” - 您只需get所有地址实体即可。这很快又便宜。

答案 1 :(得分:0)

这是数据存储区的一个非常标准的问题。解决方案是非规范化。通过允许重复,您可以将问题分解为一对多关系。因此,在您的示例中:允许Address重复,并让每个Address都有父CompanyService。或者将您的Address实体拆分为两个(ServiceAddressCompanyAddress)。

现在修改ServiceCompany时,您可以对地址执行简单的祖先查询,您只能获得相应的地址。

此方法假设您不会每秒更新Address(或您拥有的任何其他实体),因为您将遇到每秒1次写入和其他实体组。