如何对具有父子关系的模型的属性执行NDB查询?

时间:2015-03-03 19:38:48

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

所以我有一个如下所示的根模型:

class Contact(ndb.Model):
    first_name= ndb.StringProperty()
    last_name= ndb.StringProperty()
    age = ndb.IntegerProperty()

和一个看起来像这样的儿童模型:

class Address(ndb.Model)
    address_type=ndb.StringProperty(choices=['Home','Office','School'],default='Home')
    street = ndb.StringProperty()
    city = ndb.StringProperty()
    state = ndb.StringProperty()

我希望能够执行类似于此的查询:     选择first_name,last_name,street,city,state WHERE contact.age> 25和address.city =' Miami'和address_type ='学校'

我知道如果我将地址设置为联系人模型中的结构化属性,我可以更轻松地执行搜索,但我不喜欢使用结构化属性,因为他们没有自己的密钥,从而使实体维护更具挑战性。

我尝试首先搜索联系人,然后将生成的密钥提供给WHERE IN子句,但它没有用,例如:

query1 = Contact.query(Contact.age>25).iter(keys_only = True)
query2 = Address.query(Address.city=='Miami', Address.address_type=='School',Address.ancestor.IN(query1))

任何关于如何解决这个问题的想法都将受到赞赏。

2 个答案:

答案 0 :(得分:0)

您可以使用Ancestor query吗?

query1 = Contact.query(Contact.age>25).iter(keys_only = True)
for contact in query1:
    query2 = Address.query(Address.city=='Miami',
                           Address.address_type=='School',
                           ancestor=contact)

如果这还不够有效,那么过滤地址怎么样?

query1 = Contact.query(Contact.age>25).iter(keys_only = True)
contacts = set(query1)
query2 = Address.query(Address.city=='Miami', Address.address_type=='School')
addresses = [address for address in query2 if address.key.parent() in contacts]

答案 1 :(得分:0)

好吧所以看起来我通过传入另一个查询来过滤一个查询的原始想法会起作用。问题是您不能对祖先属性执行WHERE-IN子句,因此您必须将父键存储为子实体内部的标准ndb.KeyProperty(),然后执行WHERE-IN子句KeyProperty字段。

这是一个直接从Appengine SDK中的交互式控制台工作的示例:

from google.appengine.ext import ndb

class Contact(ndb.Model):
    first_name= ndb.StringProperty()
    last_name= ndb.StringProperty()
    age = ndb.IntegerProperty()


class Address(ndb.Model):
    address_type=ndb.StringProperty(choices=['Home','Office','School'],default='Home')
    street = ndb.StringProperty()
    city = ndb.StringProperty()
    state = ndb.StringProperty()
    contact = ndb.KeyProperty()


# Contact 1
contact1 = Contact(first_name='Homer', last_name='Simpson', age=45)
contact1_result = contact1.put()
contact1_address1 = Address(address_type='Home',street='742 Evergreen Terrace', city='Springfield', state='Illinois', contact=contact1_result, parent=contact1_result)
contact1_address1.put()
contact1_address2 = Address(address_type='Office',street=' 1 Industry Row', city='Springfield', state='Illinois', contact=contact1_result, parent=contact1_result)
contact1_address2.put()

# Contact 2
contact2 = Contact(first_name='Peter', last_name='Griffan', age=42)
contact2_result = contact2.put()
contact2_address1 = Address(address_type='Home',street='31 Spooner Street', city='Quahog', state='Rhode Island', contact=contact2_result, parent=contact2_result)
contact2_address1.put()

# This gets the keys of all the contacts that are over the age of 25
qry1 = Contact.query(Contact.age>25).fetch(keys_only=True)

# This query gets all addresses of type 'Home' where the contacts are in the result set of qry1
qry2 = Address.query(Address.address_type=='Home').filter(Address.contact.IN(qry1))

for item in qry2:
    print 'Contact: %s,%s,%s,%s'% (item.contact.get().first_name, item.contact.get().last_name, item.address_type, item.street)

这会产生一个看起来像这样的结果:

Contact: Peter,Griffan,Home,31 Spooner Street
Contact: Homer,Simpson,Home,742 Evergreen Terrace