针对结构化属性的NDB过滤Google App Engine

时间:2016-04-29 10:39:28

标签: python google-app-engine app-engine-ndb google-cloud-datastore google-app-engine-python

我有ndb模型:

class Product(ndb.Model):
    name = ndb.StringProperty()
    description = ndb.StringProperty()
    code = ndb.StringProperty()

class Category(ndb.Model):
    name = ndb.StringProperty()

class Shop(ndb.Model):
    name = ndb.StringProperty()
    category = ndb.StructuredProperty(Category)
    address = ndb.StringProperty()

class ProductInShop(ndb.Model):
    product = ndb.StructuredProperty(Product)
    shop = ndb.StructuredProperty(Shop)
    price = ndb.FloatProperty()

在一个功能中,我需要在商店中找到产品(产品代码和商店密钥请求)。如果店内没有产品(返回无),那么我需要创建它。 如果存在则从请求更新价格值。现在我正在通过gql进行查询。

product_in_shop = ndb.gql(
        'SELECT * FROM ProductInShop WHERE \
product.code = :1 AND shop = :2 LIMIT 1',
        request.code,
        ndb.Key(Shop, request.shop_key).get()
    ).get()

它工作正常。 但!有些时候product_in_shop = None应该有一个实体(我在数据库中检查过)。 我试图进行另一个查询以计算实体,它返回0,但是有超过1个实体。

当我看到这个包时,我可以更新(python appcfg.py -A project-name update project-name)并且它可以工作......

任何想法我做错了什么或如何解决它?

1 个答案:

答案 0 :(得分:1)

这很可能Eventual Consistency。使用Cloud Datastore设计系统时,需要规划这些查询需要时间才能变为最新的情况。可能,在这种情况下重新部署您的应用程序只需要足够的时间,以便在您再次检查时更新信息。

为了保证一致性,您需要将数据整理到实体组中。数据模型的一个重要考虑因素是,在EG中,您可以以一致的方式进行查询。但是,您只能以每秒1次更新的持续速率更新单个实体组(但此更新可能是批量更新)。

尝试沿自然边界对齐这些实体组,以帮助限制在应用程序扩展时将写入任何给定实体组的速率。例如,每个用户可能只有一个实体组,或者对于您的应用程序,每个Shop可能只有一个实体组。如果您将单个Product的所有Shop放入一个实体组中,则始终可以以强烈一致的方式列出商店中的所有Product。您无法扩大向商店添加商品的人数(您只能将商品写入商店每秒一批),但这可能是系统可接受的约束条件。

因此,请考虑以下布局:

class Product(ndb.Model):
    name = ndb.StringProperty()
    description = ndb.StringProperty()
    code = ndb.StringProperty()

class Category(ndb.Model):
    name = ndb.StringProperty()

class Shop(ndb.Model):
    name = ndb.StringProperty()
    category = ndb.StructuredProperty(Category)
    address = ndb.StringProperty()

class ProductInShop(ndb.Model):
    product = ndb.StructuredProperty(Product)
    price = ndb.FloatProperty()

当您创建ProductInShop时,您希望将父级设置为其所属的Shop的键。例如:

ProductInShop(parent=ndb.Key(Shop, request.shop_key),
    product=Product(...), price=10.0).put()

然后,您可以使用特定代码为给定商店中的一个产品发出查询:

product_in_shop = ndb.gql(
        'SELECT * FROM ProductInShop WHERE \
product.code = :1 AND ANCESTOR IS :2 LIMIT 1',
        request.code,
        ndb.Key(Shop, request.shop_key)
    ).get()

作为旁注,如果您的code对于单个产品是唯一的,请考虑将ProductInShop的ID设置为代码。然后,您不必为此发出查询:

ProductInShop(id=product.code, product=product, price=10.0).put()

然后,您可以查找ProductInShop,而无需使用以下方式发出查询:

product_in_shop = ndb.Key(Shop, request.shop_key, ProductInShop, request.code).get()