Catatan: Developer yang membangun aplikasi baru sangat dianjurkan untuk menggunakan Library Klien NDB, yang memiliki beberapa manfaat jika dibandingkan dengan library klien ini, seperti caching entity otomatis melalui Memcache API. Jika saat ini Anda menggunakan Library Klien DB versi lama, baca Panduan Migrasi DB ke NDB
Objek data di Datastore disebut sebagai entity. Entity memiliki satu atau beberapa properti yang telah diberi nama, yang masing-masing dapat memiliki satu atau beberapa nilai. Entity dari jenis yang sama tidak harus memiliki properti yang sama, dan nilai suatu entity untuk properti tertentu tidak semuanya harus memiliki jenis data yang sama. (Jika perlu, aplikasi dapat membuat dan menerapkan pembatasan tersebut dalam model datanya sendiri.)
Datastore mendukung berbagai jenis data untuk nilai properti. Hal ini mencakup, antara lain:
- Bilangan bulat
- Angka floating-point
- String
- Tanggal
- Data biner
Untuk mengetahui daftar lengkap jenis, lihat Jenis nilai dan properti.
Setiap entity dalam Datastore memiliki kunci yang secara unik mengidentifikasinya. Kunci ini terdiri dari komponen berikut:
- Namespace entity, yang memungkinkan multitenancy
- Jenis entity, yang mengategorikannya untuk tujuan kueri Datastore
- ID untuk masing-masing entity, yang dapat berupa
- string nama kunci
- ID numerik bilangan bulat
- Jalur ancestor opsional yang mencari entity dalam hierarki Datastore
Aplikasi dapat mengambil setiap entity dari Datastore menggunakan kunci entity, atau mengambil satu atau beberapa entity dengan mengeluarkan kueri berdasarkan kunci entity atau nilai properti.
Python App Engine SDK menyertakan library pemodelan data untuk menampilkan entity Datastore sebagai instance class Python, serta untuk menyimpan dan mengambil instance tersebut di Datastore.
Datastore sendiri tidak menerapkan batasan apa pun pada struktur entity, seperti apakah properti tertentu memiliki nilai dari jenis tertentu; tugas ini diserahkan ke aplikasi dan library pemodelan data.
Jenis dan ID
Setiap entity Datastore memiliki jenis tertentu, yang mengategorikan entity untuk tujuan kueri: misalnya, aplikasi sumber daya manusia mungkin mewakili setiap karyawan di sebuah perusahaan dengan entity jenis Employee
. Di Python Datastore API, jenis entity ditentukan oleh class modelnya, yang Anda tentukan dalam aplikasi sebagai subclass dari class library pemodelan data db.Model
. Nama class model menjadi jenis entity yang termasuk di dalamnya. Semua nama jenis yang dimulai dengan dua garis bawah (__
) dicadangkan dan tidak dapat digunakan.
Contoh berikut membuat entity jenis Employee
, mengisi nilai propertinya, dan menyimpannya ke Datastore:
import datetime
from google.appengine.ext import db
class Employee(db.Model):
first_name = db.StringProperty()
last_name = db.StringProperty()
hire_date = db.DateProperty()
attended_hr_training = db.BooleanProperty()
employee = Employee(first_name='Antonio',
last_name='Salieri')
employee.hire_date = datetime.datetime.now().date()
employee.attended_hr_training = True
employee.put()
Class Employee
mendeklarasikan empat properti untuk model data: first_name
, last_name
, hire_date
, dan attended_hr_training
. Superclass Model
memastikan bahwa atribut objek Employee
sesuai dengan model ini: misalnya, upaya untuk menetapkan nilai string ke atribut hire_date
akan menghasilkan error runtime karena model data untuk hire_date
dideklarasikan sebagai db.DateProperty
.
Selain jenis, setiap entity memiliki ID, yang ditetapkan saat entity dibuat. Karena ID tersebut merupakan bagian dari kunci entity, ID-nya dikaitkan secara permanen dengan entity dan tidak dapat diubah. ID tersebut dapat ditetapkan dengan salah satu dari dua cara berikut:
- Aplikasi Anda dapat menentukan string key name-nya sendiri untuk entity.
- Anda dapat meminta Datastore untuk menetapkan ID numerik bilangan bulat ke entity secara otomatis.
Untuk menetapkan nama kunci entity, berikan argumen bernama key_name
ke konstruktor class model saat Anda membuat entity:
# Create an entity with the key Employee:'asalieri'.
employee = Employee(key_name='asalieri')
Agar Datastore menetapkan ID numerik secara otomatis, hilangkan argumen key_name
:
# Create an entity with a key such as Employee:8261.
employee = Employee()
Menetapkan ID
Datastore dapat dikonfigurasi untuk menghasilkan ID otomatis menggunakan dua kebijakan ID otomatis yang berbeda:
- Kebijakan
default
menghasilkan urutan acak dari ID yang tidak digunakan yang kira-kira didistribusikan secara seragam. Setiap ID dapat memiliki maksimal 16 digit desimal. - Kebijakan
legacy
membuat urutan ID bilangan bulat yang lebih kecil dan tidak berurutan.
Jika Anda ingin menampilkan ID entity kepada pengguna, dan/atau bergantung pada urutannya, sebaiknya Anda menggunakan alokasi manual.
Datastore menghasilkan urutan acak dari ID yang tidak digunakan yang kira-kira didistribusikan secara seragam. Setiap ID dapat memiliki maksimal 16 digit desimal.
Jalur ancestor
Entity dalam Cloud Datastore membentuk ruang yang terstruktur secara hierarkis, yang menyerupai struktur direktori sistem file. Saat membuat entity, Anda dapat memilih untuk menetapkan entity lain sebagai parent;; entity barunya adalah parent; dari parent entity tersebut (perlu diperhatikan bahwa tidak seperti dalam sistem file, parent entity tidak harus benar-benar ada). Entity tanpa parent adalah root entity. Kaitan entity dan induknya bersifat permanen, dan tidak dapat diubah setelah entity tersebut dibuat. Cloud Datastore tidak akan pernah menetapkan ID numerik yang sama ke dua entity dengan parent yang sama, atau ke dua root entity (yang tidak memiliki parent).
Induk, induk dari induk, dan seterusnya dari suatu entity secara rekursif adalah ancestor-nya; turunannya, turunan dari turunannya, dan seterusnya adalah turunannya. Root entity dan semua turunannya termasuk dalam entity group yang sama. Urutan entity yang dimulai dengan root entity dan berlanjut dari parent ke turunan, yang mengarah ke entity tertentu, merupakan jalur ancestor entity tersebut. Kunci lengkap yang mengidentifikasi entity terdiri dari urutan pasangan jenis-ID yang menentukan jalur ancestor-nya dan berakhir dengan entity itu sendiri:
[Person:GreatGrandpa, Person:Grandpa, Person:Dad, Person:Me]
Untuk root entity, jalur ancestor kosong dan kuncinya hanya terdiri dari jenis dan ID entity itu sendiri:
[Person:GreatGrandpa]
Konsep ini diilustrasikan oleh diagram berikut:
Untuk menetapkan parent entity, gunakan argumen parent
ke konstruktor class model saat membuat entity turunan. Nilai argumen ini dapat berupa parent entity itu sendiri atau kuncinya; Anda bisa mendapatkan kunci dengan memanggil metode key()
parent entity. Contoh berikut membuat entity jenis Address
dan menunjukkan dua cara menetapkan entity Employee
sebagai parent-nya:
# Create Employee entity
employee = Employee()
employee.put()
# Set Employee as Address entity's parent directly...
address = Address(parent=employee)
# ...or using its key
e_key = employee.key()
address = Address(parent=e_key)
# Save Address entity to datastore
address.put()
Transaksi dan entity group
Setiap upaya untuk membuat, memperbarui, atau menghapus entity terjadi dalam konteks transaksi. Satu transaksi dapat mencakup sejumlah operasi tersebut. Untuk menjaga konsistensi data, transaksi tersebut memastikan bahwa semua operasi yang ada di dalamnya diterapkan ke Datastore sebagai unit atau, jika salah satu operasi gagal, bahwa tidak ada satu pun operasi yang diterapkan. Selain itu, semua pembacaan dengan konsistensi kuat (kueri atau pembacaan ancestor) yang dilakukan dalam transaksi yang sama akan melihat snapshot data yang konsisten.
Seperti yang telah disebutkan di atas, entity group adalah serangkaian entity yang terhubung melalui ancestry ke elemen root yang sama. Pengaturan data ke dalam entity group dapat membatasi transaksi yang dapat dilakukan:
- Semua data yang diakses oleh transaksi harus berada dalam maksimal 25 entity group.
- Jika Anda ingin menggunakan kueri dalam transaksi, data Anda harus diatur ke dalam entity group sedemikian rupa sehingga Anda dapat menentukan filter ancestor yang akan cocok dengan data yang tepat.
- Ada batas throughput operasi tulis sekitar satu transaksi per detik dalam satu entity group. Batasan ini diberikan karena Datastore melakukan replikasi sinkron tanpa master untuk setiap entity group di area geografis yang luas guna memberikan keandalan dan fault tolerance yang tinggi.
Dalam banyak penerapan, Anda dapat menggunakan konsistensi tertunda (yaitu kueri non-ancestor yang mencakup beberapa entity group, yang terkadang menampilkan data yang sedikit usang) saat mengambil pandangan yang luas tentang data yang tidak terkait, kemudian menggunakan konsistensi yang kuat (kueri ancestor atau get
dari satu entity) saat melihat atau mengedit satu set data yang sangat terkait. Dalam penerapan semacam itu, sebaiknya Anda menggunakan entity group yang terpisah untuk setiap set data yang sangat terkait.
Untuk informasi selengkapnya, lihat Membuat Struktur untuk Konsistensi Kuat.
Properti dan jenis nilai
Nilai data yang terkait dengan entity terdiri dari satu atau beberapa properti. Setiap properti memiliki nama dan satu atau beberapa nilai. Properti dapat memiliki nilai yang berisi lebih dari satu jenis, dan dua entity dapat memiliki nilai dari jenis yang berbeda untuk properti yang sama. Properti dapat diindeks atau tidak diindeks (kueri yang mengurutkan atau memfilter pada properti P akan mengabaikan entity jika P tidak diindeks). Entity dapat memiliki maksimal 20.000 properti yang diindeks.
Jenis nilai berikut ini didukung:
Jenis nilai | Jenis Python | Tata urutan | Notes |
---|---|---|---|
Bilangan Bulat | int long |
Angka | Bilangan bulat 64-bit, ditandai |
Angka floating-point | float |
Angka | Presisi ganda 64-bit, IEEE 754 |
Boolean | bool |
False <True |
|
String teks (singkat) | str unicode |
Unicode ( str diperlakukan sebagai ASCII) |
Hingga 1.500 byte |
String teks (panjang) | db.Text |
Tidak ada | Hingga 1 megabyte Tidak diindeks |
String byte (pendek) | db.ByteString |
Urutan byte | Hingga 1.500 byte |
String byte (panjang) | db.Blob |
Tidak ada | Hingga 1 megabyte Tidak diindeks |
Tanggal dan waktu | datetime.date datetime.time datetime.datetime |
Kronologis | |
Titik geografis | db.GeoPt |
Berdasarkan lintang, lalu bujur |
|
Alamat pos | db.PostalAddress |
Unicode | |
Nomor telepon | db.PhoneNumber |
Unicode | |
Alamat email | db.Email |
Unicode | |
Pengguna Akun Google | users.User |
Alamat email berdasarkan urutan Unicode |
|
Handle fitur pesan instan | db.IM |
Unicode | |
Link | db.Link |
Unicode | |
Kategori | db.Category |
Unicode | |
Rating | db.Rating |
Angka | |
Kunci Datastore | db.Key |
Menurut elemen jalur (jenis, ID, jenis, ID...) |
|
Kunci Blobstore | blobstore.BlobKey |
Urutan byte | |
Null | NoneType |
Tidak ada |
Penting: Sebaiknya jangan menyimpan UserProperty
karena berisi alamat email dan ID unik pengguna. Jika pengguna mengubah alamat emailnya dan Anda membandingkan
User
lamanya yang tersimpan dengan nilai User
yang baru, nilai tersebut tidak akan cocok.
Untuk string teks dan data biner yang tidak dienkode (string byte), Datastore mendukung dua jenis nilai:
- String pendek (hingga 1.500 byte) diindeks dan dapat digunakan dalam kondisi filter kueri dan tata urutan.
- String panjang (hingga 1 megabyte) tidak diindeks serta tidak dapat digunakan dalam filter kueri dan tata urutan.
Blob
di Datastore API. Jenis ini tidak terkait dengan blob seperti yang digunakan dalam Blobstore API.
Jika kueri melibatkan properti dengan nilai jenis campuran, Datastore akan menggunakan pengurutan deterministik berdasarkan representasi internal:
- Nilai null
- Angka fixed-point
- Bilangan bulat
- Tanggal dan waktu
- Rating
- Nilai boolean
- Urutan byte
- String byte
- String Unicode
- Kunci Blobstore
- Angka floating-point
- Titik geografis
- Pengguna Akun Google
- Kunci Datastore
Karena string teks panjang dan string byte panjang tidak diindeks, maka pengurutan tidak ditentukan.
Bekerja dengan entity
Aplikasi dapat menggunakan Datastore API untuk membuat, mengambil, memperbarui, dan menghapus entity. Jika aplikasi mengetahui kunci lengkap untuk suatu entity (atau dapat memperolehnya dari kunci, jenis, dan ID parent-nya), aplikasi dapat menggunakan kunci tersebut untuk beroperasi secara langsung pada entity. Aplikasi juga bisa memperoleh kunci entity sebagai hasil dari kueri Datastore; lihat halaman Kueri Datastore untuk informasi selengkapnya.
Membuat entity
Di Python, Anda membuat entity baru dengan membuat instance class model, mengisi propertinya jika perlu, dan memanggil metode put()
untuk menyimpannya ke Datastore. Anda dapat menetapkan nama kunci entity dengan meneruskan argumen key_name ke konstruktor:
employee = Employee(key_name='asalieri',
first_name='Antonio',
last_name='Salieri')
employee.hire_date = datetime.datetime.now().date()
employee.attended_hr_training = True
employee.put()
Jika Anda tidak memberikan nama kunci, Datastore akan otomatis menghasilkan ID numerik untuk kunci entity tersebut:
employee = Employee(first_name='Antonio',
last_name='Salieri')
employee.hire_date = datetime.datetime.now().date()
employee.attended_hr_training = True
employee.put()
Mengambil entity
Untuk mengambil entity yang diidentifikasi oleh kunci tertentu, teruskan objek Key
sebagai argumen ke fungsi db.get()
. Anda dapat menghasilkan objek Key
menggunakan metode class Key.from_path()
.
Jalur lengkap adalah urutan entity di jalur ancestor, dengan setiap entity diwakili oleh jenisnya (string), diikuti dengan ID-nya (nama kunci atau ID numerik):
address_k = db.Key.from_path('Employee', 'asalieri', 'Address', 1)
address = db.get(address_k)
db.get()
menampilkan instance class model yang sesuai. Pastikan Anda telah mengimpor class model untuk entity yang diambil.
Memperbarui entity
Untuk memperbarui entity yang ada, ubah atribut objek, lalu panggil metode put()
. Data objek akan menimpa entity yang ada. Seluruh objek dikirim ke Datastore pada setiap panggilan ke put()
.
Untuk menghapus properti, hapus atribut dari objek Python:
del address.postal_code
kemudian simpan objek tersebut.
Menghapus entity
Dengan kunci entity, Anda dapat menghapus entity dengan fungsi db.delete()
address_k = db.Key.from_path('Employee', 'asalieri', 'Address', 1)
db.delete(address_k)
atau dengan memanggil metode delete()
entity sendiri:
employee_k = db.Key.from_path('Employee', 'asalieri')
employee = db.get(employee_k)
# ...
employee.delete()
Operasi batch
Fungsi db.put()
, db.get()
, dan db.delete()
(beserta fungsi asinkronnya db.put_async()
, db.get_async()
, dan db.delete_async()
) dapat menerima argumen daftar untuk bertindak pada beberapa entity dalam satu panggilan Datastore:
# A batch put.
db.put([e1, e2, e3])
# A batch get.
entities = db.get([k1, k2, k3])
# A batch delete.
db.delete([k1, k2, k3])
Operasi batch tidak mengubah biaya Anda. Anda akan dikenai biaya untuk setiap kunci dalam operasi batch, terlepas dari apakah setiap kunci ada atau tidak. Ukuran entity yang terlibat dalam operasi tidak memengaruhi biaya.
Menghapus entity secara massal
Jika Anda perlu menghapus entity dalam jumlah besar, sebaiknya gunakan Dataflow untuk menghapus entity secara massal.
Menggunakan daftar kosong
Untuk antarmuka NDB, Datastore secara historis menulis daftar kosong sebagai properti yang dihilangkan untuk properti statis dan dinamis. Untuk mempertahankan kompatibilitas mundur, perilaku ini akan terus menjadi default. Untuk menggantinya baik secara global atau per ListProperty, tetapkan argumen write_empty_list ketrue
di class Properti Anda; daftar kosong kemudian ditulis ke Datastore dan dapat dibaca sebagai daftar kosong.
Untuk antarmuka DB, penulisan daftar kosong secara historis tidak diizinkan sama sekali jika properti bersifat dinamis: jika Anda mencobanya, Anda akan mendapatkan error. Artinya, tidak ada perilaku default yang perlu dipertahankan untuk kompatibilitas mundur bagi properti dinamis DB, sehingga Anda dapat menulis dan membaca daftar kosong dalam model dinamis tanpa perlu mengubah apa pun.
Namun, untuk properti statis DB, daftar kosong ditulis sebagai properti yang dihilangkan, dan perilaku ini berlanjut secara default untuk kompatibilitas mundur.
Jika Anda ingin mengaktifkan daftar kosong untuk properti statis DB, gunakan argumen write_empty_list ke true
di class Properti Anda; daftar kosong tersebut kemudian ditulis ke Datastore.