1. query():要注意query()是回傳Query物件,還不是Entities
我們可以使用 query() 方法在Google Cloud Datastore中搜尋特定條件的entities。
class Greeting(ndb.Model):
"""Models an individual Guestbook entry with content and date."""
content = ndb.StringProperty()
date = ndb.DateTimeProperty(auto_now_add=True)
@classmethod
def query_book(cls, ancestor_key):
return cls.query(ancestor=ancestor_key).order(-cls.date)
class MainPage(webapp2.RequestHandler):
GREETINGS_PER_PAGE = 20
def get(self):
guestbook_name = self.request.get('guestbook_name')
ancestor_key = ndb.Key('Book', guestbook_name or '*notitle*')
greetings = Greeting.query_book(ancestor_key).fetch(self.GREETINGS_PER_PAGE)
self.response.out.write('<html><body>')
for greeting in greetings:
self.response.out.write('<blockquote>%s</blockquote>' % cgi.escape(greeting.content))
self.response.out.write('</body></html>')
* Client端送出含guestbook_name參數的HTTP GET,Server端以Key('kind', id)得到符合的guestbook的key,並以搜尋這個guestbook底下的message。
* cgi.espcape()將字串的HTML character entities轉成escape sequence。
query物件可以使用filter()做更進一步搜尋。
query1 = Account.query() # Retrieve all Account entitites
query2 = query1.filter(Account.userid >= 40) # Filter on userid >= 40
另外還有order()方法進行排序。
query = Greeting.query().order(Greeting.content, -Greeting.date) ## 負號代表降序
最後以fetch()方法得到所有符合query的entities,fetch()可傳入數字代表回傳前幾個entities就好。
2. 搜尋條件:
基本上就是長這樣:model.query(model.property == value),也可以使用 !=、>、<、>=...等常見比較符號。
比較特別的是IN, model.property.IN([value1, value2]),這個意思等同 (model.property==value1) OR (model.property==value2)。
若要使用多條件只要使用逗點隔開就好,例如: Student.query(Student.age > 10, Student.age <= 12)。
也可使用多個AND與OR,但太過複雜的條件的話易會報錯,要經過正規化再使用,下面是官方的例子:
query = Article.query(ndb.AND(Article.tags == 'python',
ndb.OR(Article.tags.IN(['ruby', 'jruby']),
ndb.AND(Article.tags == 'php',
Article.tags != 'perl'))))
正規化步驟:(1) 將 IN 與 != 展開,property.IN([a, b])等同OR(property==a, property==b),property!=a等同OR(property>a, property<a)
(2) AND(a, b, OR(c, d)) -> OR(AND(a, b, c), AND(a, b, d)):
(3) AND(a, b, AND(c, d)) -> AND(a, b, c, d):
(4) OR(a, b, OR(c, d)) -> OR(a, b, c, d):
結果:
OR(AND(tags == 'python', tags == 'ruby'),
AND(tags == 'python', tags == 'jruby'),
AND(tags == 'python', tags == 'php', tags < 'perl'),
AND(tags == 'python', tags == 'php', tags > 'perl'))
3. Ancestor Query:
ancestor的設計幫助我們的資料有更高的一致性,但其有個缺點,在同個ancestor下的entities在寫入時每秒只能有一次寫入 (entities with the same ancestor are limited to 1 write per second)。
來看看下面兩種例子:
(1) non-ancestor example:
class Customer(ndb.Model):
name = ndb.StringProperty()
class Purchase(ndb.Model):
customer = ndb.KeyProperty(kind=Customer)
price = ndb.IntegerProperty()
purchases = Purchase.query(Purchase.customer == customer_entity.key).fetch()
這樣的寫法能讓我們快速寫入,但只是eventual consistency,我們只能得到新寫入的purchase。(2) ancestor example:
class Customer(ndb.Model):
name = ndb.StringProperty()
class Purchase(ndb.Model):
price = ndb.IntegerProperty()
purchases = Purchase(parent=customer_entity.key).fetch()
每個purchase key上會依附這一 customer key,如此才能以customer搜尋到底下相關的purchases。4. 使用字串來得到property:
property_to_query = 'location'
query = FlexEmployee.query(ndb.GenericProperty(property_to_query) == 'SF') ## Expando
query = Article.query(Article._properties[keyword] == value)
query = Article.query(getattr(Article, keyword) == value)
5. Query Cursors:
query內部的指針。使用fetch_page()回傳一triple:(results, cursor, more) ,more是一個flag代表是否還有其他的結果,
直接看Code比較好懂。
from google.appengine.datastore.datastore_query import Cursor
class List(webapp2.RequestHandler):
GREETINGS_PER_PAGE = 10
def get(self):
"""Handles requests like /list?cursor=1234567."""
cursor = Cursor(urlsafe=self.request.get('cursor'))
greets, next_cursor, more = Greeting.query().fetch_page(
self.GREETINGS_PER_PAGE, start_cursor=cursor)
self.response.out.write('<html><body>')
for greeting in greets:
self.response.out.write('<blockquote>%s</blockquote>' % cgi.escape(greeting.content))
if more and next_cursor:
self.response.out.write('<a href="https://www.blogger.com/list?cursor=%s">More...</a>' %
next_cursor.urlsafe())
self.response.out.write('</body></html>')
* Note the use of urlsafe() and Cursor(urlsafe=s) to serialize and deserialize the cursor.
6. Calling a Function for each Entity ("Mapping"):
使用map(callback)能做到平行加速。
### slow ###
message_account_pairs = []
for message in message_query:
key = ndb.Key('Account', message.userid)
account = key.get()
message_account_pairs.append((message, account))
### faster ####
def callback(message):
key = ndb.Key('Account', message.userid)
account = key.get()
message_account_pairs = message_query.map(callback)
7. GQL:
GQL類似SQL語言,用來取Google Cloud Datastore中的entities。
(1) ndb.gql(querystring) 回傳 Query object
(2) Model.gql(querystring) is a shorthand for ndb.gql("SELECT * FROM Model " + querystring).
參考資料:
1. 官方資料:https://cloud.google.com/appengine/docs/standard/python/ndb/queries
沒有留言:
張貼留言