Datastore-Abfragen

Hinweis: Entwicklern von neuen Anwendungen wird dringend empfohlen, die NDB-Clientbibliothek zu verwenden. Diese bietet im Vergleich zur vorliegenden Clientbibliothek verschiedene Vorteile, beispielsweise das automatische Caching von Entitäten über die Memcache API. Wenn Sie derzeit die ältere DB-Clientbibliothek verwenden, lesen Sie die Anleitung zur Migration von DB zu NDB.

Bei einer Datastore-Abfrage werden Entitäten aus Cloud Datastore abgerufen, die einen Satz von angegebenen Bedingungen erfüllen.

Eine typische Abfrage umfasst:

  • eine Entitätsart, auf die die Abfrage angewendet wird,
  • optionale Filter, die auf den Attributwerten, Schlüsseln und Ancestors der Entität beruhen, und
  • optionale Sortierfolgen zur Anordnung der Ergebnisse.
Bei der Ausführung ruft die Abfrage alle Entitäten des angegebenen Typs ab, die alle Filterbedingungen erfüllen, und sortiert sie in der angegebenen Reihenfolge. Abfragen werden ohne Schreibberechtigung ausgeführt.

Auf dieser Seite werden die Struktur und Arten von Abfragen beschrieben, die in App Engine zum Abrufen von Daten aus Cloud Datastore verwendet werden.

Filter

Die Filter einer Abfrage legen Einschränkungen für die Attribute, Schlüssel und Ancestors der Entitäten fest, die abgerufen werden sollen.

Attributfilter

In einem Attributfilter wird Folgendes angegeben:

  • Ein Attributname
  • Ein Vergleichsoperator
  • Ein Attributwert
Beispiel:

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

Der Property-Wert muss von der Anwendung angegeben werden; er kann keine anderen Properties referenzieren oder anhand anderer Properties berechnet werden. Eine Entität erfüllt den Filter, wenn sie eine Property mit dem angegebenen Namen enthält, deren Wert mit dem in dem Filter angegebenen Wert in der vom Vergleichsoperator beschriebenen Weise verglichen wird.

Einer der folgenden Vergleichsoperatoren kann verwendet werden:

Operator Bedeutung
= Gleich
< Kleiner als
<= Kleiner als oder gleich
> Größer als
>= Größer als oder gleich
!= Ungleich
IN Element von (entspricht einem der Werte in einer angegebenen Liste)

Mit dem Operator "ungleich" (!=) werden tatsächlich zwei Abfragen ausgeführt: eine Abfrage, bei der alle anderen Filter unverändert bleiben und statt des Filters "ungleich" der Filter "kleiner als" (<) verwendet wird, und eine weitere Abfrage, bei der anstelle von "ungleich" der Filter "größer als" (>) verwendet wird. Danach werden die Ergebnisse in der entsprechenden Reihenfolge zusammengeführt. Eine Abfrage darf nur einen Not-equal-Filter enthalten, und wenn das der Fall ist, darf sie keine anderen Ungleichheitsfilter enthalten.

Mit dem Operator IN werden ebenfalls mehrere Abfragen ausgeführt: Eine für jedes Element in der angegebenen Liste, wobei alle anderen Filter unverändert bleiben und der Filter IN durch einen Gleichheitsfilter (=) ersetzt wird. Die Ergebnisse werden in der Reihenfolge der Elemente in der Liste zusammengeführt. Wenn eine Abfrage mehr als einen IN-Filter enthält, werden mehrere Abfragen ausgeführt, und zwar jeweils eine für jede mögliche Kombination von Werten in den IN-Listen.

Eine einzelne Abfrage mit den Operatoren "ungleich" (!=) oder IN ist auf 30 Unterabfragen begrenzt.

Schlüsselfilter

Zur Filterung mit dem Wert eines Entitätsschlüssels verwenden Sie die besondere Property __key__:

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

Bei einem Vergleich auf Ungleichheit werden die Schlüssel nach den folgenden Kriterien in folgender Reihenfolge angeordnet:

  1. Ancestor-Pfad
  2. Entitätsart
  3. Kennzeichnung (Schlüsselname oder numerische ID)

Elemente des Ancestor-Pfads werden ähnlich verglichen: nach Art (String), dann nach Schlüsselname oder numerischer ID. Arten und Schlüsselnamen sind Strings und werden nach Bytewert sortiert, numerische IDs sind Ganzzahlen und werden numerisch sortiert. Wenn Entitäten mit derselben übergeordneten Entität und derselben Art eine Mischung aus Schlüsselnamen-Strings und numerischen IDs verwenden, stehen die Entitäten mit numerischen IDs vor den Entitäten mit Schlüsselnamen.

Abfragen auf Schlüssel verwenden genau wie Abfragen auf Attribute Indexe und erfordern in denselben Fällen benutzerdefinierte Indexe, allerdings mit einigen Ausnahmen: Ungleichheitsfilter oder eine aufsteigende Sortierfolge für Schlüssel erfordern keinen benutzerdefinierten Index, eine absteigende Sortierfolge für Schlüssel hingegen schon. Wie bei allen Abfragen erstellt der Entwicklungs-Webserver entsprechende Einträge in der Indexkonfigurationsdatei, wenn eine Abfrage, die einen benutzerdefinierten Index erfordert, getestet wird.

Ancestor-Filter

Sie können Datastore-Abfragen mit einem bestimmten Ancestor filtern, sodass die zurückgegebenen Ergebnisse nur untergeordnete Entitäten von diesem Ancestor enthalten:

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

Besondere Abfragetypen

Einige spezifische Abfragetypen müssen besonders erwähnt werden:

Typlose Abfragen

Mit einer typlosen Abfrage ohne Ancestor-Filter werden alle Entitäten einer Anwendung aus Datastore abgerufen. Dazu gehören auch Entitäten, die durch andere App Engine-Features erstellt und verwaltet werden, beispielsweise Statistikentitäten und Blobstore-Metadatenentitäten (sofern vorhanden). Derartige typlose Abfragen können keine Filter oder Sortierfolgen für Attributwerte enthalten. Sie können jedoch zum Filtern von Entitätsschlüsseln verwendet werden, wenn Sie __key__ als Attributname angeben:

q = db.Query()
q.filter('__key__ >', last_seen_key)

In Python muss für jede von der Abfrage zurückgegebene Entität eine entsprechende Modellklasse für den Typ der Entität definiert sein. Sie müssen das stats-Paket importieren, um die Modellklassen für die statistischen Entitätsarten zu definieren:

from google.appengine.ext.db import stats

Wenn Ihre Anwendung über einen Blobstore-Wert verfügt, müssen Sie den folgenden Code hinzufügen, damit die Abfrage-API den Entitätstyp __BlobInfo__ erkennt. (Beim Importieren der Blobstore-API wird diese Klasse nicht definiert.)

from google.appengine.ext import db

class BlobInfo(db.Expando):
  @classmethod
  def kind(cls):
    return '__BlobInfo__'

Ancestor-Abfragen

Bei einer Abfrage mit einem Ancestor-Filter sind die Ergebnisse auf die angegebene Entität und ihre Nachfolger begrenzt:

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

Typlose Ancestor-Abfragen

Mit einer typlosen Abfrage, die einen Ancestor-Filter enthält, werden der angegebene Ancestor und alle seine untergeordneten Entitäten unabhängig vom Typ abgerufen. Für diesen Abfragetyp sind keine benutzerdefinierten Indexe erforderlich. Wie alle typlosen Abfragen dürfen sie keine Filter oder Sortierfolgen für Property-Werte enthalten, das Filtern auf den Schlüssel der Entität ist jedoch möglich:

q = db.Query()
q.ancestor(ancestor_key)
q.filter('__key__ >', last_seen_key)

Wenn Sie in der Verwaltungskonsole von App Engine oder mit der GqlQuery-Klasse eine typlose Ancestor-Abfrage mit GQL ausführen möchten, lassen Sie die FROM-Klausel weg:

q = db.GqlQuery('SELECT * WHERE ANCESTOR IS :1 AND __key__ > :2',
                ancestor_key,
                last_seen_key)

Im folgenden Beispiel wird gezeigt, wie alle untergeordneten Entitäten eines bestimmten Ancestors abgerufen werden:

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

Ausschließlich schlüsselbasierte Abfragen

Eine ausschließlich schlüsselbasierte Abfrage gibt nur die Schlüssel der Ergebnisentitäten statt der Entitäten selbst mit einer niedrigeren Latenz und niedrigeren Kosten zurück.

q = Person.all(keys_only=True)

Häufig ist es wirtschaftlicher, zuerst eine ausschließlich schlüsselbasierte Abfrage durchzuführen und dann einen Teil der Entitäten aus den Ergebnissen abzurufen, als eine allgemeine Abfrage auszuführen, die mehr Entitäten abrufen kann, als tatsächlich benötigt werden.

Projektionsabfragen

Manchmal benötigen Sie aus den Ergebnissen einer Abfrage eigentlich nur die Werte einiger bestimmter Attribute. In solchen Fällen haben Sie die Möglichkeit, mit einer Projektionsabfrage nur die Attribute abzurufen, die Sie tatsächlich interessieren. Dies führt zu niedrigerer Latenz und geringeren Kosten als beim Abruf ganzer Entitäten. Weitere Informationen dazu finden Sie auf der Seite zu Projektionsabfragen.

Sortierfolgen

Eine Abfrage-Sortierfolge gibt Folgendes an:

  • Ein Attributname
  • Eine Sortierfolge (aufsteigend oder absteigend)

In Python wird die absteigende Sortierfolge durch einen Bindestrich (-) vor dem Propertynamen angegeben. Durch das Weglassen des Bindestrichs wird standardmäßig die aufsteigende Reihenfolge angegeben. Beispiel:

# Order alphabetically by last name:
q = Person.all()
q.order('last_name')

# Order by height, tallest to shortest:
q = Person.all()
q.order('-height')

Wenn eine Abfrage mehrere Sortierfolgen enthält, werden diese in der angegebenen Abfolge angewendet. Im folgenden Beispiel wird zuerst aufsteigend nach Nachname und dann absteigend nach Körpergröße sortiert:

q = Person.all()
q.order('lastName')
q.order('-height')

Wenn keine Sortierfolgen angegeben werden, werden die Ergebnisse in der Reihenfolge zurückgeliefert, in der sie aus Cloud Datastore abgerufen werden.

Hinweis: Aufgrund der Art, wie Cloud Datastore Abfragen ausführt, muss Folgendes beachtet werden: Wenn in einer Abfrage Ungleichheitsfilter für ein Attribut und Sortierfolgen für andere Attribute angegeben sind, muss das Attribut, das mit Ungleichheitsfiltern verwendet wird, vor den anderen Attributen sortiert werden.

Indexe

Bei jeder Datastore-Abfrage werden die Ergebnisse anhand eines oder mehrerer Indexe berechnet, die Entitätsschlüssel in einer von den Indexattributen vorgegebenen Reihenfolge und optional auch Ancestors der Entität enthalten. Diese Indexe werden inkrementell aktualisiert, um die von den Anwendungen durchgeführten Änderungen an den Entitäten widerzuspiegeln und so ohne weitere Berechnung exakte Ergebnisse für alle Abfragen zur Verfügung zu stellen.

App Engine gibt für jedes Attribut einer Entität einen einfachen Index vor. Eine App Engine-Anwendung kann weitere benutzerdefinierte Indexe in der Indexkonfigurationsdatei index.yaml definieren. Der Entwicklungsserver fügt dieser Datei automatisch Vorschläge hinzu, wenn er Abfragen ermittelt, die mit den vorhandenen Indexen nicht ausgeführt werden können. Sie können die Indexe vor dem Hochladen der Anwendung von Hand optimieren.

Beispiel einer Abfrageschnittstelle

Die Datastore API von Python bietet zwei Klassen zum Vorbereiten und Ausführen von Abfragen:

  • Query verwendet Methodenaufrufe zur Vorbereitung der Abfrage.
  • GqlQuery verwendet eine SQL-ähnliche Abfragesprache mit dem Namen GQL zur Vorbereitung der Abfrage aus einem Abfragestring.

    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)
    

Weitere Informationen

Hat Ihnen diese Seite weitergeholfen? Teilen Sie uns Ihr Feedback mit:

Feedback geben zu...

App Engine-Standardumgebung für Python 2