Kueri Proyeksi

Sebagian besar kueri Datastore menampilkan seluruh entitas sebagai hasilnya, tetapi seringkali 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 Java 8

Untuk membuat kueri proyeksi, buat objek Query dan tambahkan properti ke objek tersebut menggunakan metode addProjection():

private void addGuestbookProjections(Query query) {
  query.addProjection(new PropertyProjection("content", String.class));
  query.addProjection(new PropertyProjection("date", Date.class));
}

Jenis yang Anda tentukan untuk setiap properti harus cocok dengan jenis yang Anda gunakan saat pertama kali menentukan properti dengan Entity.setProperty(). Contoh berikut menunjukkan cara memproses hasil kueri dengan melakukan iterasi melalui daftar entity yang ditampilkan dan mentransmisikan setiap nilai properti ke jenis yang diharapkan:

private void printGuestbookEntries(DatastoreService datastore, Query query, PrintWriter out) {
  List<Entity> guests = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(5));
  for (Entity guest : guests) {
    String content = (String) guest.getProperty("content");
    Date stamp = (Date) guest.getProperty("date");
    out.printf("Message %s posted on %s.\n", content, stamp.toString());
  }
}

Pengelompokan(eksperimental)

Kueri proyeksi dapat menggunakan metode setDistinct() untuk memastikan bahwa hanya hasil yang benar-benar unik yang akan ditampilkan dalam kumpulan hasil. Tindakan ini hanya akan menampilkan hasil pertama untuk entity yang memiliki nilai yang sama untuk properti yang sedang diproyeksikan.

Query q = new Query("TestKind");
q.addProjection(new PropertyProjection("A", String.class));
q.addProjection(new PropertyProjection("B", Long.class));
q.setDistinct(true);
q.setFilter(Query.FilterOperator.LESS_THAN.of("B", 1L));
q.addSort("B", Query.SortDirection.DESCENDING);
q.addSort("A");

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 (EQUAL) 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).

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

    Karena kueri menampilkan hasil yang hanya terisi sebagian, Anda tidak boleh 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, datastore-indexes-auto.xml, 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.