Query Cursor

Query Cursor memudahkan aplikasi mengambil hasil kueri dalam batch, dan lebih direkomendasikan daripada penggunaan offset bilangan bulat untuk penomoran halaman. Lihat Kueri untuk mengetahui informasi selengkapnya tentang pembuatan struktur kueri untuk aplikasi Anda.

Query Cursor

Query Cursor memudahkan aplikasi mengambil hasil kueri dalam batch tanpa menimbulkan overhead offset kueri. Setelah melakukan operasi pengambilan, aplikasi dapat memperoleh kursor, yang merupakan string yang dienkode sebagai base64 bersifat opaque yang menandai posisi indeks hasil terakhir yang diambil. Aplikasi dapat menyimpan string ini, misalnya di Datastore, di Memcache, di payload tugas Task Queue, atau disematkan di halaman web sebagai parameter GET atau POST HTTP, dan dapat menggunakan kursor sebagai titik awal untuk operasi pengambilan berikutnya guna mendapatkan batch hasil berikutnya dari titik akhir pengambilan sebelumnya. Pengambilan juga dapat menentukan kursor akhir untuk membatasi sejauh mana kumpulan hasil yang ditampilkan.

Offset versus kursor

Meskipun Datastore mendukung offset bilangan bulat, Anda harus menghindari penggunaannya. Sebagai gantinya, gunakan kursor. Penggunaan offset hanya akan menghindari ditampilkannya entity yang dilewati ke aplikasi Anda, tetapi entity ini masih diambil secara internal. Entity yang dilewati memengaruhi latensi kueri dan aplikasi Anda akan dikenai biaya untuk operasi baca yang diperlukan untuk mengambil dokumen tersebut. Dengan menggunakan kursor, bukan offset, Anda dapat menghindari semua biaya ini.

Contoh Query Cursor

Di Go, aplikasi memperoleh kursor setelah mengambil hasil kueri dengan memanggil metode Cursor nilai Iterator. Untuk mengambil hasil tambahan dari titik kursor, aplikasi menyiapkan kueri serupa dengan jenis entity, filter, dan tata urutan entity yang sama, serta meneruskan kursor ke metode Start kueri sebelum melakukan pengambilan:

// Create a query for all Person entities.
q := datastore.NewQuery("Person")

// If the application stored a cursor during a previous request, use it.
item, err := memcache.Get(ctx, "person_cursor")
if err == nil {
	cursor, err := datastore.DecodeCursor(string(item.Value))
	if err == nil {
		q = q.Start(cursor)
	}
}

// Iterate over the results.
t := q.Run(ctx)
for {
	var p Person
	_, err := t.Next(&p)
	if err == datastore.Done {
		break
	}
	if err != nil {
		log.Errorf(ctx, "fetching next Person: %v", err)
		break
	}
	// Do something with the Person p
}

// Get updated cursor and store it for next time.
if cursor, err := t.Cursor(); err == nil {
	memcache.Set(ctx, &memcache.Item{
		Key:   "person_cursor",
		Value: []byte(cursor.String()),
	})
}

Batasan kursor

Kursor tunduk pada batasan berikut:

  • Kursor hanya dapat digunakan oleh aplikasi yang sama yang menjalankan kueri asli, dan hanya untuk melanjutkan kueri yang sama. Untuk menggunakan kursor dalam operasi pengambilan berikutnya, Anda harus menyusun ulang kueri asli dengan tepat, termasuk jenis entity, filter ancestor, filter properti, dan tata urutan yang sama. Anda tidak dapat mengambil hasil menggunakan kursor tanpa menyiapkan kueri yang sama dengan kueri yang membuat kursor tersebut.
  • Kursor tidak selalu berfungsi seperti yang diharapkan dengan kueri yang menggunakan filter ketidaksetaraan atau tata urutan pada properti dengan beberapa nilai. Logika de-duplikasi untuk properti multi-nilai tersebut tidak akan dipertahankan di antara pengambilan, yang mungkin menyebabkan hasil yang sama ditampilkan lebih dari sekali.
  • Rilis App Engine baru dapat mengubah detail implementasi internal, sehingga membatalkan validasi kursor yang bergantung padanya. Jika aplikasi mencoba menggunakan kursor yang tidak lagi valid, Datastore akan menampilkan error.

Kursor dan pembaruan data

Posisi kursor ditentukan sebagai lokasi dalam daftar hasil setelah hasil terakhir ditampilkan. Kursor bukan merupakan posisi relatif dalam daftar (bukan offset); kursor adalah penanda yang dapat dilewati Datastore saat memulai pemindaian indeks untuk mendapatkan hasil. Jika hasil kueri berubah di antara penggunaan kursor, kueri hanya akan melihat perubahan yang terjadi dalam hasil setelah kursor. Jika hasil baru muncul sebelum posisi kursor untuk kueri, hasil tersebut tidak akan ditampilkan jika hasilnya baru muncul setelah kursor diambil. Demikian pula, jika suatu entity bukan lagi hasil kueri, tetapi telah muncul sebelum kursor, hasil yang muncul setelah kursor tidak berubah. Jika hasil terakhir yang ditampilkan dihapus dari kumpulan hasil, kursor masih mengetahui cara menemukan hasil berikutnya.

Saat mengambil hasil kueri, Anda dapat menggunakan kursor awal dan kursor akhir untuk menampilkan grup hasil berkelanjutan dari Datastore. Saat menggunakan kursor awal dan akhir untuk mengambil hasil, tidak ada jaminan bahwa ukuran hasilnya akan sama seperti saat membuat kursor. Entity dapat ditambahkan atau dihapus dari Datastore antara saat kursor dibuat dan saat kursor digunakan dalam kueri.

Apa langkah selanjutnya?