Kueri Proyeksi

Sebagian besar kueri Datastore menampilkan seluruh entity sebagai hasilnya, tetapi sering kali aplikasi sebenarnya hanya tertarik pada beberapa properti entity. Kueri proyeksi memungkinkan Anda membuat kueri Datastore hanya untuk properti tertentu tersebut dari entity yang benar-benar Anda butuhkan, dengan latensi dan biaya yang lebih rendah daripada mengambil seluruh entity.

Kueri proyeksi mirip dengan kueri SQL berbentuk:

SELECT name, email, phone FROM CUSTOMER

Anda dapat menggunakan semua fitur pemfilteran dan pengurutan yang tersedia untuk kueri entity standar, sesuai dengan batasan yang dijelaskan di bawah. Kueri menampilkan hasil ringkas hanya dengan properti yang ditentukan (name, email, dan phone dalam contoh) yang diisi dengan nilai; semua properti lainnya tidak memiliki data.

Menggunakan kueri proyeksi di Python 2

Pertimbangkan model berikut:

class Article(ndb.Model):
    title = ndb.StringProperty()
    author = ndb.StringProperty()
    tags = ndb.StringProperty(repeated=True)

Anda menentukan proyeksi dengan cara ini:

def print_author_tags():
    query = Article.query()
    articles = query.fetch(20, projection=[Article.author, Article.tags])
    for article in articles:
        print(article.author)
        print(article.tags)
        # article.title will raise a ndb.UnprojectedPropertyError

Anda menangani hasil kueri ini seperti yang Anda lakukan untuk kueri entity standar: misalnya, dengan melakukan iterasi pada hasilnya.

for article in articles:
        print(article.author)
        print(article.tags)
        # article.title will raise a ndb.UnprojectedPropertyError

Anda dapat memproyeksikan sub-properti yang diindeks dari properti terstruktur. Untuk mendapatkan properti city saja dari properti terstruktur address kontak, Anda dapat menggunakan proyeksi seperti:

class Address(ndb.Model):
    type = ndb.StringProperty()  # E.g., 'home', 'work'
    street = ndb.StringProperty()
    city = ndb.StringProperty()
...
class Contact(ndb.Model):
    name = ndb.StringProperty()
    addresses = ndb.StructuredProperty(Address, repeated=True)
...
Contact.query().fetch(projection=["name", "addresses.city"])
Contact.query().fetch(projection=[Contact.name, Contact.addresses.city])

Pengelompokan(eksperimental)

Kueri proyeksi dapat menggunakan kata kunci distinct untuk memastikan bahwa hanya hasil yang benar-benar unik yang akan ditampilkan dalam kumpulan hasil. Tindakan ini hanya akan menampilkan hasil pertama untuk entity dengan nilai yang sama untuk properti yang sedang diproyeksikan.

Article.query(projection=[Article.author], group_by=[Article.author])
Article.query(projection=[Article.author], distinct=True)

Kedua kueri tersebut setara dan hanya akan membuat nama setiap penulis satu kali.

Batasan proyeksi

Kueri proyeksi tunduk pada batasan berikut ini:

  • Hanya properti yang diindeks yang dapat diproyeksikan.

    Proyeksi tidak didukung untuk properti yang tidak diindeks, baik secara eksplisit maupun implisit. String teks panjang (Text) dan string byte panjang (Blob) tidak diindeks.

  • Properti yang sama tidak dapat diproyeksikan lebih dari sekali.

  • Properti yang direferensikan dalam filter kesetaraan (=) atau keanggotaan (IN) tidak dapat diproyeksikan.

    Misalnya,

    SELECT A FROM kind WHERE B = 1
    

    valid (properti yang diproyeksikan tidak digunakan dalam filter kesetaraan), begitu juga

    SELECT A FROM kind WHERE A > 1
    

    (bukan filter kesetaraan), tetapi

    SELECT A FROM kind WHERE A = 1
    

    (properti proyeksi yang digunakan dalam filter kesetaraan) tidak valid.

  • Hasil yang ditampilkan oleh kueri proyeksi tidak dapat disimpan kembali ke Datastore.

    Karena kueri menampilkan hasil yang hanya terisi sebagian, Anda tidak dapat menulisnya kembali ke Datastore.

Proyeksi dan properti multi-nilai

Memproyeksikan properti dengan beberapa nilai tidak akan mengisi semua nilai untuk properti tersebut. Sebagai gantinya, entity terpisah akan ditampilkan untuk setiap kombinasi unik dari nilai proyeksi yang cocok dengan kueri. Misalnya, Anda memiliki entity jenis Foo dengan dua properti multi-nilai, yaitu A dan B:

entity = Foo(A=[1, 1, 2, 3], B=['x', 'y', 'x'])

Kemudian, kueri proyeksi

SELECT A, B FROM Foo WHERE A < 3

akan menampilkan empat entity dengan kombinasi nilai berikut:

A = 1, B = 'x'
A = 1, B = 'y'
A = 2, B = 'x'
A = 2, B = 'y'

Perhatikan bahwa jika suatu entity memiliki properti multi-nilai tanpa nilai, tidak ada entri yang akan disertakan dalam indeks, dan tidak ada hasil untuk entity tersebut yang akan ditampilkan dari kueri proyeksi yang menyertakan properti tersebut.

Indeks untuk proyeksi

Kueri proyeksi mengharuskan semua properti yang ditentukan dalam proyeksi untuk disertakan dalam indeks Datastore. Server pengembangan App Engine secara otomatis menghasilkan indeks yang diperlukan untuk Anda di file konfigurasi indeks, index.yaml, yang diupload dengan aplikasi Anda.

Salah satu cara untuk meminimalkan jumlah indeks yang diperlukan adalah dengan memproyeksikan properti yang sama secara konsisten, meskipun tidak semuanya selalu diperlukan. Misalnya, kueri ini memerlukan dua indeks terpisah:

SELECT A, B FROM Kind
SELECT A, B, C FROM Kind

Namun, jika Anda selalu memproyeksikan properti A, B, dan C, meskipun C tidak diperlukan, hanya satu indeks yang akan diperlukan.

Mengonversi kueri yang ada menjadi kueri proyeksi mungkin memerlukan pembuatan indeks baru jika properti dalam proyeksi belum disertakan pada bagian kueri yang lain. Sebagai contoh, misalnya Anda memiliki kueri yang ada seperti

SELECT * FROM Kind WHERE A > 1 ORDER BY A, B

yang memerlukan indeks

Index(Kind, A, B)

Mengonversi ini ke salah satu kueri proyeksi

SELECT C FROM Kind WHERE A > 1 ORDER BY A, B
SELECT A, B, C FROM Kind WHERE A > 1 ORDER BY A, B

memperkenalkan properti baru (C) sehingga akan memerlukan pembuatan indeks baru Index(Kind, A, B, C). Perhatikan bahwa kueri proyeksi

SELECT A, B FROM Kind WHERE A > 1 ORDER BY A, B

tidak akan mengubah indeks yang diperlukan, karena properti yang diproyeksikan, yaitu A dan B, sudah disertakan dalam kueri yang ada.