StructuredProperty是否引用父或子?
class Invoices(ndb.Model): #Child
class Customers(ndb.Model): #Parent
invoice = ndb.StructuredProperty(Invoices)
...或
class Customers(ndb.Model): #Parent
class Invoices(ndb.Model): #Child
customer = ndb.StructuredProperty(Customers)
答案 0 :(得分:3)
要在“NoSQL数据存储的更佳实践是什么”的上下文中回答您的问题, 这就是我能提供的。
首先,您可能希望以单数形式命名模型,因为它们应该描述单个模型
Invoice
或Customer
实体,而不是几个。
接下来,使用StructuredProperty
意味着您希望将所有这些信息保存在
单个实体 - 这将减少写/读操作,但可能会引入一些限制。
(见docs -
或者这个related question)
最常见的关系是一个(Customer
)到多个(Invoice
)关系,
您可以如下构建:
class Invoice(ndb.Model): #Child
invoice_id = ndb.StringProperty(required=True) #
class Customer(ndb.Model): #Parent
invoices = ndb.StructuredProperty(Invoices, repeated=True)
def get_invoice_by_id(self, invoice_id):
"""Returns a customer Invoice by invoice_id. Raises KeyError if invoice is not present."""
invoice_matches = [iv for iv in self.invoices if iv.invoice_id == invoice_id]
if not invoice_matches: raise KeyError("Customer has no Invoice with ID %s" % invoice_id)
return invoice_matches[0] # this could be changed to return all matches
请记住以下对此实施的限制:
StructuredProperty
s内部不能包含重复的属性。invoice_id
全局唯一的复杂性将高于Invoice
在其自己的实体组中的复杂性。 (invoice_key.get()
始终优于此要求的查询))Customer
上的实例方法才能Invoice
找到invoice_id
。Customer
以下是一些优点:
Customer
Invoice
查询invoice_id
将返回Customer
个实例以及所有发票。 (这可能是专业人士和骗子,实际上 - 你需要逻辑来从客户那里退回发票)这是一个更常见的解决方案,但绝不一定是“正确的解决方案”。
此解决方案使用祖先关系,允许您保持对Invoice
和。{
相关的Customer
原子 - 所以你可以维护总计发票统计数据
Customer
级别。 (total_orders
,total_gross
等。)
class Invoice(ndb.Model):
customer = ndb.ComputedProperty(lambda self: self.key.parent(), indexed=False) # when not indexed, this is essentially a @property
class Customer(ndb.Model):
def get_invoice_by_id(self, invoice_id):
"""Returns a customer Invoice by invoice_id. Raises KeyError if invoice is not present."""
invoice_key = ndb.Key(Invoice._get_kind(), invoice_id, parent=self.key)
return invoice_key.get()
def query_invoices(self):
"""Returns ndb.Query for invoices by this Customer."""
return self.query(ancestor=self.key)
invoice = Invoice(parent=customer.key, **invoice_properties)
Appengine祝你好运!一旦掌握了所有这些,它就是一个真正有益的平台。
<强>更新强>
如上所述,以下是一些用于事务性更新客户总计的其他代码。
def create_invoice(customer_key, gross_amount_paid):
"""Creates an invoice for a given customer.
Args:
customer_key: (ndb.Key) Customer key
gross_amount_paid: (int) Gross amount paid by customer
"""
@ndb.transactional
def _txn():
customer = customer_key.get()
invoice = Invoice(parent=customer.key, gross_amount=gross_amount_paid)
# Keep an atomic, transactional count of customer aggregates
customer.total_gross += gross_amount_paid
customer.total_orders += 1
# batched put for API optimization
ndb.put_multi([customer, invoice])
return invoice
return _txn()
上述代码适用于single entity group transaction
(例如ndb.transactional(xg=False)
),因为Invoice
是Customer
的子实体。如果该连接丢失,则需要xg=True
。 (我不确定它是否更贵,但它不太优化)