Kueri Datastore

Catatan: Developer yang membuat aplikasi baru sangat dianjurkan untuk menggunakan Library Klien NDB, yang memiliki beberapa manfaat dibandingkan dengan library klien ini, seperti menyimpan entity dalam cache secara otomatis melalui Memcache API. Jika saat ini Anda menggunakan Library Klien DB versi lama, baca Panduan Migrasi DB ke NDB

Kueri Datastore mengambil entity dari Cloud Datastore yang memenuhi kumpulan kondisi tertentu.

Kueri umumnya mencakup hal berikut:

  • Jenis entity yang menerapkan kueri
  • Filter opsional berdasarkan nilai properti, kunci, dan ancestor entity
  • Tata urutan opsional untuk mengurutkan hasil
Saat dieksekusi, kueri mengambil semua entity dari jenis tertentu yang memenuhi semua filter yang diberikan, yang diurutkan dalam urutan yang ditentukan. Kueri dijalankan sebagai hanya baca.

Halaman ini menjelaskan struktur dan jenis kueri yang digunakan dalam App Engine untuk mengambil data dari Cloud Datastore.

Filter

Filter kueri menetapkan batasan pada properti, kunci, dan ancestor dari entity yang akan diambil.

Filter properti

Filter properti menentukan

  • Nama properti
  • Operator perbandingan
  • Nilai properti
Contoh:

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

Nilai properti harus diberikan oleh aplikasi; ini tidak bisa merujuk ke atau dihitung dari segi properti lainnya. Entity memenuhi filter jika memiliki properti dengan nama tertentu yang nilainya dibandingkan dengan nilai yang ditentukan dalam filter dengan cara yang dijelaskan oleh operator perbandingan.

Operator perbandingan dapat berupa salah satu dari yang berikut:

Operator Arti
= Sama dengan
< Kurang dari
<= Kurang dari atau sama dengan
> Lebih dari
>= Lebih dari atau sama dengan
!= Tidak sama dengan
IN Anggota (sama dengan nilai mana pun dalam daftar yang ditentukan)

Operator not-equal (!=) sebenarnya menjalankan dua kueri: salah satunya ketika semua filter lain tidak berubah dan filter not-equal diganti dengan filter less-than (<) , dan satunya lagi yang diganti dengan filter greater-than (>) . Hasilnya kemudian digabungkan, secara berurutan. Kueri tidak boleh memiliki lebih dari satu filter not-equal dan kueri yang memiliki filter tersebut tidak boleh memiliki filter ketidaksetaraan lainnya.

Operator IN juga menjalankan beberapa kueri: satu untuk setiap item dalam daftar yang ditentukan, dengan semua filter lainnya tidak berubah dan filter IN diganti dengan filter kesetaraan (=) . Hasilnya digabungkan sesuai urutan item dalam daftar. Jika kueri memiliki lebih dari satu filter IN, kueri tersebut akan dijalankan seperti beberapa kueri, satu untuk setiap kemungkinan kombinasi nilai yang ada dalam daftar IN singkat ini.

Satu kueri yang berisi operator not-equal (!=) atau IN dibatasi hingga maksimum 30 subkueri.

Filter kunci

Untuk memfilter nilai kunci entity, gunakan properti khusus __key__:

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

Saat membandingkan ketidaksetaraan, kunci diurutkan berdasarkan kriteria berikut secara berurutan:

  1. Jalur ancestor
  2. Jenis entity
  3. ID (nama kunci atau ID numerik)

Elemen jalur ancestor dibandingkan dengan cara serupa: berdasarkan jenis (string), lalu menurut nama kunci atau ID numerik. Jenis dan nama kunci merupakan string dan diurutkan berdasarkan nilai byte; ID numerik adalah bilangan bulat dan diurutkan secara numerik. Jika entity dengan induk dan jenis yang sama menggunakan campuran string nama kunci dan ID numerik, entity dengan ID numerik akan mendahului nama kunci tersebut.

Kueri pada kunci menggunakan indeks seperti kueri pada properti dan memerlukan indeks kustom dalam kasus yang sama, dengan beberapa pengecualian: filter ketidaksetaraan atau tata urutan menaik pada kunci tidak memerlukan indeks kustom, tetapi adanya tata urutan menurun pada kunci. Seperti halnya semua kueri, server web pengembangan akan membuat entri yang sesuai dalam file konfigurasi indeks saat kueri yang memerlukan indeks kustom sedang diuji.

Filter ancestor

Anda dapat memfilter kueri Datastore ke ancestor yang ditentukan, sehingga hasil yang ditampilkan hanya akan menyertakan entity yang diturunkan dari ancestor tersebut:

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

Jenis kueri khusus

Beberapa jenis kueri tertentu perlu disebutkan secara khusus:

Kueri tanpa jenis

Kueri tanpa jenis dan filter ancestor mengambil semua entity aplikasi dari Datastore. Ini termasuk entity yang dibuat dan dikelola oleh fitur App Engine lainnya, seperti entity statistik dan entity metadata Blobstore (jika ada). Kueri tanpa jenis tersebut tidak boleh menyertakan filter atau tata urutan pada nilai properti. Namun, kueri tersebut dapat memfilter kunci entity dengan menentukan __key__ sebagai nama properti:

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

Di Python, setiap entity yang ditampilkan oleh kueri harus memiliki class model yang sesuai dan yang ditentukan untuk jenis entity. Untuk menentukan class model untuk jenis entity statistik, Anda harus mengimpor paket stats:

from google.appengine.ext.db import stats

Jika aplikasi Anda memiliki nilai Blobstore, Anda harus menambahkan kode berikut agar query API dapat mengenali jenis entity __BlobInfo__. (Mengimpor Blobstore API tidak menentukan class ini.)

from google.appengine.ext import db

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

Kueri ancestor

Kueri dengan filter ancestor membatasi hasilnya ke entity yang ditentukan dan turunannya:

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

Kueri ancestor tanpa jenis

Kueri tanpa jenis yang menyertakan filter ancestor akan mengambil ancestor yang ditentukan dan semua turunannya, apa pun jenisnya. Jenis kueri ini tidak memerlukan indeks kustom. Seperti semua kueri tanpa jenis, kueri tidak dapat menyertakan filter atau tata urutan pada nilai properti, tetapi dapat memfilter kunci entity:

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

Untuk menjalankan kueri ancestor tanpa jenis menggunakan GQL (di Konsol Administrasi App Engine atau menggunakan class GqlQuery), hapus klausa FROM:

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

Contoh berikut menggambarkan cara mengambil semua entity yang merupakan turunan dari ancestor tertentu:

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

Kueri khusus kunci

Kueri khusus kunci hanya menampilkan kunci entity hasil, bukan entity itu sendiri, dengan latensi dan biaya yang lebih rendah daripada mengambil seluruh entity:

q = Person.all(keys_only=True)

Sering kali lebih ekonomis untuk melakukan kueri khusus kunci terlebih dahulu, lalu mengambil subset entity dari hasil, daripada menjalankan kueri umum yang dapat mengambil lebih banyak entity daripada yang sebenarnya Anda butuhkan.

Kueri proyeksi

Terkadang yang sangat Anda perlukan dari hasil kueri adalah nilai dari beberapa properti tertentu. Dalam kasus seperti itu, Anda dapat menggunakan kueri proyeksi untuk mengambil properti yang benar-benar Anda minati saja, dengan latensi dan biaya yang lebih rendah daripada mengambil seluruh entity; lihat halaman Kueri Proyeksi untuk mengetahui detailnya.

Tata urutan

Tata urutan kueri menentukan

  • Nama properti
  • Arah pengurutan (menaik atau menurun)

Di Python, tata urutan menurun dilambangkan dengan tanda hubung (-) sebelum nama properti; menghilangkan tanda hubung untuk menentukan urutan naik secara default. Contoh:

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

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

Jika kueri menyertakan beberapa tata urutan, maka akan diterapkan dalam urutan yang ditentukan. Contoh berikut mengurutkan nama belakang secara menaik, lalu mengurutkan tinggi secara menurun:

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

Jika tidak ada tata urutan yang ditentukan, hasilnya akan ditampilkan sesuai urutan pengambilannya dari Datastore.

Catatan: Karena cara Datastore mengeksekusi kueri, jika kueri menentukan filter ketidaksetaraan di properti dan tata urutan di properti lain, properti yang digunakan dalam filter ketidaksetaraan harus diurutkan sebelum properti lainnya.

Indeks

Setiap Datastore kueri menghitung hasilnya menggunakan satu atau beberapa indeks dan yang berisi kunci entity dalam urutan yang ditentukan oleh properti indeks dan, secara opsional, ancestor entity. Indeks diperbarui secara bertahap untuk mencerminkan setiap perubahan yang dilakukan aplikasi pada entity-nya, sehingga hasil yang benar dari semua kueri tersedia tanpa perlu komputasi lebih lanjut.

App Engine menentukan terlebih dahulu indeks sederhana di setiap properti entity. Aplikasi App Engine dapat menentukan indeks kustom lebih lanjut dalam file konfigurasi indeks bernama index.yaml. Server pengembangan secara otomatis menambahkan saran ke file ini karena menemukan kueri yang tidak dapat dijalankan dengan indeks yang ada. Anda dapat menyesuaikan indeks secara manual dengan mengedit file sebelum mengupload aplikasi.

Contoh antarmuka kueri

Python Datastore API menyediakan dua class untuk menyiapkan dan mengeksekusi kueri:

  • Query menggunakan panggilan metode untuk menyiapkan kueri.
  • GqlQuery menggunakan bahasa kueri seperti SQL yang disebut GQL untuk menyiapkan kueri dari string kueri.
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)

Apa langkah selanjutnya?