資料儲存庫查詢

附註:強烈建議建構新應用程式的開發人員使用NDB 用戶端程式庫,相較於此用戶端程式庫,NDB 用戶端程式庫有幾項優點,例如能透過 Memcache API 自動快取實體。如果您目前使用的是舊版 DB 用戶端程式庫,請參閱 DB 至 NDB 遷移指南

資料儲存庫的「查詢」 會自滿足特定條件的 Cloud Datastore 中擷取 實體

典型的查詢包含以下幾項:

執行時,查詢會擷取滿足所有指定篩選器的指定種類實體,並按照指定的順序進行排序。查詢執行屬於唯讀狀態。

本頁面說明在應用程式引擎中,用於從 Cloud Datastore 擷取資料的查詢結構和種類。

篩選器

查詢的「篩選器」對實體的屬性金鑰以及祖系設定限制,以便擷取所需內容。

屬性篩選器

「屬性篩選器」指定

  • 屬性名稱
  • 比較運算子
  • 屬性值
例如:

q = Person.all()
q.filter("height <=", max_height)

屬性值必須由應用程式提供,不能參考或由其他屬性的術語計算。若實體具有指定名稱的屬性,則實體會滿足篩選器。(該屬性的值與篩選器中指定的值進行比較時,以比較運算子來表示)。

比較運算子可以為以下任何一種:

運算子 意義
= 等於
< 小於
<= 小於或等於
> 大於
>= 大於或等於
!= 不等於
IN 成員 (與指定列表中的任何值相等)

不等 (!=) 運算子實際上執行兩個查詢:一個是在其他所有篩選器皆未變更的情況下, 「不等於」 篩選器會替換為 「小於」 的篩選器 (<)。另一個是會替換為 「大於」(>) 的篩選器。並將結果合併並排序。查詢中只能有一個 「不等於」 篩選器,且一個查詢中不能有任何其他的不等於篩選器。

IN 運算子能夠執行多個 查詢:一個指定列表中的每個項目,列表中所有其他篩選器 未受變更,且將 IN 篩選器替換為 「等於」(=) 篩選器。結果會依照列表中項目的順序進行合併。若查詢中包含 多個 IN 篩選器,則會以多個查詢執行, 每個查詢對應於 IN 列表中每個可能值之 「組合」

單一查詢包含 不等於 (!=) 或上限為 30 個子查詢的 IN 運算子。

金鑰篩選器

若要篩選實體金鑰的值,請使用特殊屬性 __key__

q = Person.all()
q.filter('__key__ >', last_seen_key)

在比較不等式時,金鑰會根據以下標準進行排序:

  1. 祖系路徑
  2. 實體種類
  3. ID (金鑰名稱或數字型 ID)

祖系路徑元素的比較方式很相近:按照種類 (字串),然後按照金鑰名稱或數字型 ID。種類和金鑰名稱為字串,且會按照位元組值進行排序,數字型 ID 會按照數字進行排序。若具有相同父級和種類的實體使用金鑰名稱字串與數字型 ID 的混合,數字型 ID 必須置於金鑰名稱之前。

對金鑰的查詢使用索引就如同對屬性的查詢,在相同情況下使用所需的自定義索引,但有幾個例外:金鑰的不等式篩選器或遞增排列不需要自定義篩選器,但是金鑰的遞減排列則需要。與所有查詢相同,當要測試需要自定義索引的查詢時,開發網頁伺服器會在索引設置檔案中建立合適的實體。

祖系篩選器

您可以將資料儲存庫查詢篩選為特定的祖系,因此回傳的結果僅包含來自於該祖系的實體。

q = Person.all()
q.ancestor(ancestor_key)

特殊查詢類型

請特別注意一些特定型態的查詢:

無種類的查詢

沒有種類且沒有祖系篩選器的查詢會從資料儲存庫中擷取應用程式的所有實體。這包含其他 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 (無論在應用程式引擎管理控制台或使用 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')

若未指定排序順序,則會按照從 Cloud DataStore 擷取的順序傳回結果。

附註:因為 Cloud Datastore 執行查詢的方式,若查詢對屬性指定不對等篩選器,並對其他屬性進行排序,則在不對等篩選中使用的屬性必須排序在其他屬性之前。

索引

每個資料儲存庫的查詢使用一個或多個「索引」(包含由索引的屬性以及 (可選) 實體的祖系指定之序列中的實體金鑰) 計算其結果。索引會逐步地更新,以反映應用程式對其實體所做的任何更改,因此所有查詢的正確結果皆可用,且無需再進一步計算。

應用程式引擎會針對實體的每個屬性預先定義簡單的索引。應用程式引擎可以在名為 index.yaml索引設置檔案中定義更多自定義的索引。開發伺服器遇到無法使用現有索引執行的查詢時,會自動在此檔案中新增建議。您可在上載應用程式之前編輯該檔案,手動調整索引。

查詢介面範例

Python Datastore API 提供兩個類別用來準備及執行查詢:

  • Query 使用方法呼叫以準備查詢。
  • GqlQuery 使用類似 SQL 的查詢語言 GQL,從查詢字串中準備查詢。

    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)
    

後續步驟

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Python 2 適用的 App Engine 標準環境