附註:我們強烈建議建構新應用程式的開發人員使用 NDB 用戶端程式庫,因為 NDB 用戶端程式庫與本用戶端程式庫相較之下有幾個優點,例如能透過 Memcache API 自動將實體加入快取。如果您目前使用的是舊版的 DB 用戶端程式庫,請參閱從 DB 至 NDB 的遷移指南。
Datastore 的「查詢」會從 Cloud Datastore 中擷取符合一組特定條件的實體。
典型的查詢包含以下幾項:
執行查詢時,查詢會擷取屬於指定種類且符合所有指定篩選器的所有實體,並按照指定順序排序。查詢會以唯讀方式執行。本頁說明在 App Engine 中,用於從 Cloud Datastore 擷取資料的查詢結構和種類。
篩選器
屬性篩選器
「屬性篩選器」指定
- 屬性名稱
- 比較運算子
- 屬性值
q = Person.all() q.filter("height <=", max_height)
屬性值必須由應用程式提供,不能參照其他屬性或以其他屬性計算得出。如果實體具有指定名稱的屬性,且屬性值與篩選器中指定的值比較,符合比較運算子描述的方式,則該實體符合篩選器的條件。
比較運算子可以為以下任何一種:
運算子 | 含義 |
---|---|
= |
等於 |
< |
小於 |
<= |
小於或等於 |
> |
大於 |
>= |
大於或等於 |
!= |
不等於 |
IN |
成員 (與指定清單中的任何值相等) |
不等於 (!=
) 運算子實際上會執行兩項查詢:一項查詢中的其他篩選器皆未變更,「不等於」篩選器會替換為「小於」(<
) 篩選器,另一項則是會替換為「大於」(>
) 篩選器。然後系統會將結果合併並排序。查詢中只能有一個「不等於」篩選器,且一個查詢中不能有任何其他的不等式篩選器。
IN
運算子也會執行多個查詢:指定清單中的各個項目各有一項查詢,而其他篩選器均未經過變更,且 IN
篩選器已替換為「等於」(=
) 篩選器。結果會依照清單中項目的順序進行合併。如果查詢中包含多個 IN
篩選器,則會以多項查詢執行,每項查詢會對應至 IN
清單中每個可能的值「組合」。
包含 not-equal (!=
) 或 IN
運算子的單一查詢上限為 30 個子查詢。
金鑰篩選器
如要篩選實體索引鍵的值,請使用特殊屬性 __key__
:
q = Person.all()
q.filter('__key__ >', last_seen_key)
在比較不等式時,金鑰會根據以下標準進行排序:
- 祖系路徑
- 實體種類
- ID (索引鍵名稱或數字 ID)
祖系路徑元素的比較方式類似:依序先比較種類 (字串),再比較索引鍵名稱或數字 ID。種類和索引鍵名稱都是按位元組值排序的字串;數字 ID 是按數字排序的整數。若父項和種類相同的實體混用索引鍵名稱和數字 ID,則會先列出採用數字 ID 的實體,再列出採用索引鍵名稱的實體。
金鑰查詢像屬性查詢一樣會使用索引,而且在相同情況下都需要自訂索引,只有少數例外狀況:不等式篩選器或金鑰遞增排序不需使用自訂索引,但金鑰遞減排序則必須使用。與所有查詢相同,當測試需要自訂索引的查詢時,開發網路伺服器會在索引設定檔中建立適當的項目。
祖系篩選器
您可以將 Datastore 查詢篩選為指定的祖系,傳回的結果就會只包含來自指定祖系的實體:
q = Person.all()
q.ancestor(ancestor_key)
特殊查詢類型
請特別注意下列幾種特定查詢類型:
無種類查詢
沒有種類且沒有祖系篩選器的查詢,會從 Datastore 中擷取應用程式的所有實體,包括其他 App Engine 功能建立及代管的實體,例如統計資料實體和 Blobstore 中繼資料實體 (如有)。這類「無種類查詢」不能對屬性值使用篩選器或進行排序。不過,這類查詢可以將 __key__
指定為屬性名稱,藉此篩選實體索引鍵:
q = db.Query()
q.filter('__key__ >', last_seen_key)
在 Python 中,查詢返回的每個實體必須擁有相對應的模型類別 (實體種類所定義)。如要定義統計資料實體類型的模型類別,您必須匯入 stats
套件:
from google.appengine.ext.db import stats
如果應用程式含有 Blobstore 值,您必須新增下列程式碼,才能取得查詢 API 來辨識 __BlobInfo__
實體類型。(匯入 Blobstore API 無法定義此類別。)
from google.appengine.ext import db
class BlobInfo(db.Expando):
@classmethod
def kind(cls):
return '__BlobInfo__'
祖系查詢
採用祖系篩選器的查詢會將結果限制在指定的實體和其子系:
tom = Person(key_name='Tom')
wedding_photo = Photo(parent=tom)
wedding_photo.image_url='http://domain.com/some/path/to/wedding_photo.jpg'
wedding_photo.put()
baby_photo = Photo(parent=tom)
baby_photo.image_url='http://domain.com/some/path/to/baby_photo.jpg'
baby_photo.put()
dance_photo = Photo(parent=tom)
dance_photo.image_url='http://domain.com/some/path/to/dance_photo.jpg'
dance_photo.put()
camping_photo = Photo()
camping_photo.image_url='http://domain.com/some/path/to/camping_photo.jpg'
camping_photo.put()
photo_query = Photo.all()
photo_query.ancestor(tom)
# This returns wedding_photo, baby_photo, and dance_photo,
# but not camping_photo, because tom is not an ancestor
for photo in photo_query.run(limit=5):
# Do something with photo
無種類祖系查詢
無論種類為何,包含祖系篩選器的無種類查詢將會擷取指定的祖系及其所有子系。這類查詢不需要自訂索引。如同所有無種類查詢,這類查詢不能對屬性值使用篩選器或進行排序,但是可以篩選實體索引鍵:
q = db.Query()
q.ancestor(ancestor_key)
q.filter('__key__ >', last_seen_key)
如要使用 GQL (無論是在 App Engine 管理控制台或使用 GqlQuery
類別) 執行無種類祖系查詢,請省略 FROM
子句:
q = db.GqlQuery('SELECT * WHERE ANCESTOR IS :1 AND __key__ > :2',
ancestor_key,
last_seen_key)
以下範例說明如何擷取指定祖系的所有實體:
tom = Person(key_name='Tom')
wedding_photo = Photo(parent=tom)
wedding_photo.image_url='http://domain.com/some/path/to/wedding_photo.jpg'
wedding_photo.put()
wedding_video = Video(parent=tom)
wedding_video.video_url='http://domain.com/some/path/to/wedding_video.avi'
wedding_video.put()
# The following query returns both weddingPhoto and weddingVideo,
# even though they are of different entity kinds
media_query = db.query_descendants(tom)
for media in media_query.run(limit=5):
# Do something with media
僅限金鑰查詢
「僅限金鑰查詢」僅傳回結果實體的金鑰而非實體本身,與擷取整個實體相比,延遲及成本都較低。
q = Person.all(keys_only=True)
先執行僅有金鑰的查詢,並從結果中獲取實體的子集,通常較為經濟實惠。您不需執行一般查詢而得到多餘的實體。
投影查詢
有時候,您只需要用到查詢結果中幾項特定屬性的值。在這種情況下,使用「投影查詢」就能只擷取實際所需屬性。相較於擷取整個實體,這個方式的延遲情況較少,費用也較為低廉。詳情請參閱「投影查詢」頁面。
排序順序
查詢的「排序順序」指定
- 屬性名稱
- 排序方向 (遞增或遞減)
在 Python 中,遞減排序順序會在屬性名稱前面加上連字號 (-
) 表示;如果省略連字號,系統會預設以遞增順序排序。例如:
# Order alphabetically by last name: q = Person.all() q.order('last_name') # Order by height, tallest to shortest: q = Person.all() q.order('-height')
如果查詢包含多個排序順序,他們將按照指定的順序排序。下列範例會先將「last name」遞增排列,再將「height」遞減排列:
q = Person.all() q.order('lastName') q.order('-height')
如果未指定排序順序,則會按照從 Datastore 擷取的順序傳回結果。
附註:由於 Datastore 執行查詢的方式,如果查詢指定以不等式篩選條件篩選某個屬性,同時指定其他屬性的排序順序,則在不等式篩選條件中使用的屬性,順序必須在其他屬性之前。
索引
每個 Datastore 查詢會使用一或多個索引 (包含由索引屬性指定的實體金鑰序列,以及實體祖系 (選用)) 計算結果。索引會逐步更新並反映應用程式針對實體進行的任何更改,以利提供所有查詢的正確結果,不需再進一步運算。
應用程式引擎會針對實體的每個屬性預先定義簡單的索引。App Engine 應用程式可在名為 index.yaml
的索引設定檔中進一步定義自訂索引。開發伺服器遇到無法使用現有索引執行的查詢時,即會自動在這個檔案中新增建議。您可在上載應用程式之前編輯設定檔,以手動調整索引。
查詢介面範例
Python Datastore API 提供兩個類別用來準備及執行查詢:
class Person(db.Model):
first_name = db.StringProperty()
last_name = db.StringProperty()
city = db.StringProperty()
birth_year = db.IntegerProperty()
height = db.IntegerProperty()
# Query interface constructs a query using instance methods
q = Person.all()
q.filter("last_name =", "Smith")
q.filter("height <=", max_height)
q.order("-height")
# GqlQuery interface constructs a query using a GQL query string
q = db.GqlQuery("SELECT * FROM Person " +
"WHERE last_name = :1 AND height <= :2 " +
"ORDER BY height DESC",
"Smith", max_height)
# Query is not executed until results are accessed
for p in q.run(limit=5):
print "%s %s, %d inches tall" % (p.first_name, p.last_name, p.height)
後續步驟
- 瞭解如何指定查詢傳回的內容,以及如何進一步控制查詢結果。
- 瞭解進行 Cloud Datastore 查詢時的常見限制。
- 瞭解查詢游標,應用程式可運用這項功能分批擷取查詢結果,十分方便。
- 瞭解資料一致性,以及如何將資料一致性運用於不同類型的 Cloud Datastore 查詢。