Metadata

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

Datastore menyediakan akses terprogram ke beberapa metadatanya untuk mendukung metaprogramming, menerapkan fungsi administratif backend, menyederhanakan caching yang konsisten, dan tujuan serupa; Anda dapat menggunakannya, misalnya, untuk membangun penampil Datastore kustom untuk aplikasi Anda. Metadata yang tersedia mencakup informasi tentang entity group, namespace, jenis entity, dan properti yang digunakan aplikasi Anda, serta representasi properti untuk setiap properti.

Dasbor Datastore di Konsol Google Cloud juga menyediakan beberapa metadata tentang aplikasi Anda, tetapi data yang ditampilkan di sana berbeda dalam beberapa hal penting dengan yang ditampilkan oleh fungsi-fungsi ini.

  • Keaktualan. Membaca metadata menggunakan API akan mendapatkan data saat ini, sedangkan data di dasbor hanya diperbarui sekali sehari.
  • Daftar Isi. Beberapa metadata di dasbor tidak tersedia melalui API; dan sebaliknya.
  • Kecepatan. Aktivitas dan kueri Metadata ditagih dengan cara yang sama seperti aktivitas dan kueri Datastore. Kueri metadata yang mengambil informasi tentang namespace, jenis, dan properti umumnya lambat untuk dijalankan. Pada dasarnya, perkirakan bahwa kueri metadata yang menampilkan entity N akan memerlukan waktu yang sama seperti N kueri biasa yang masing-masing menampilkan satu entity. Selain itu, kueri representasi properti (kueri properti khusus non-kunci) lebih lambat dari kueri properti khusus kunci. Metadata yang diperoleh metadata entity group agak lebih cepat daripada mendapatkan entity reguler.

Fungsi bantuan

Fungsi berikut memperoleh informasi metadata:

  • get_entity_group_version() mendapatkan nomor versi untuk entity group; hal ini berguna untuk mengetahui apakah ada entity dalam grup yang telah berubah sejak terakhir kali Anda mendapatkan nomor versi.
  • get_namespaces() menampilkan daftar yang berisi nama semua namespace aplikasi atau namespace yang berada dalam rentang yang ditentukan.
  • get_kinds() menampilkan daftar yang berisi nama semua jenis entity aplikasi atau jenis entity yang ada dalam rentang tertentu.
  • get_properties_of_kind() menampilkan daftar yang berisi nama semua properti terindeks aplikasi (atau properti yang berada dalam rentang tertentu) yang terkait dengan jenis entity tertentu. Properti yang tidak diindeks tidak disertakan.
  • get_representations_of_kind() menampilkan kamus yang berisi representasi untuk semua properti terindeks aplikasi atau properti dalam rentang tertentu yang terkait dengan jenis entity tertentu. Kamus memetakan nama setiap properti ke daftar representasi properti tersebut. Properti yang tidak diindeks tidak disertakan.

Metadata entity group

Cloud Datastore menyediakan akses ke "versi" entity group, angka yang benar-benar positif yang dijamin akan meningkat pada setiap perubahan pada entity group tersebut.

Contoh berikut menunjukkan cara mendapatkan versi entity group:

from google.appengine.ext import db
from google.appengine.ext.db import metadata

class Simple(db.Model):
  x = db.IntegerProperty()

entity1 = Simple(x=11)
entity1.put()

# Print entity1's entity group version
print 'version', metadata.get_entity_group_version(entity1)

# Write to a different entity group
entity2 = Simple(x=22)
entity2.put()

# Will print the same version, as entity1's entity group has not changed
print 'version', metadata.get_entity_group_version(entity1)

# Change entity1's entity group by adding a new child entity
entity3 = Simple(x=33, parent=entity1.key())
entity3.put()

# Will print a higher version, as entity1's entity group has changed
print metadata.get_entity_group_version(entity1)

Perilaku lama

Dalam perilaku versi entity group lama, versi entity group hanya meningkat saat terjadi perubahan pada entity group. Perilaku metadata entity group lama dapat digunakan, misalnya, untuk menjaga cache yang konsisten dari kueri ancestor yang kompleks di suatu entity group.

Contoh ini menyimpan hasil kueri ke dalam cache (jumlah hasil yang cocok) dan menggunakan perilaku lama versi entity group untuk menggunakan nilai yang di-cache jika nilai tersebut terbaru:

from google.appengine.api import memcache
from google.appengine.ext import db
from google.appengine.ext.db import metadata

def count_entity_group(entity_group_key):
  """Count the entities in the specified entity group."""
  # Check if we have a cached version of the current entity group count
  cached = memcache.get(str(entity_group_key))
  if cached:
    (version, count) = cached
    # Is the cached value for the current version?
    if version == metadata.get_entity_group_version(entity_group_key):
      return count

  def tx():
    # Need to actually count entities. Using a transaction to get a consistent
    # count and entity group version.
    count = db.Query(keys_only=True).ancestor(entity_group_key).count(limit=5000)
    # Cache the count and the entity group version
    version = metadata.get_entity_group_version(entity_group_key)
    memcache.set(str(entity_group_key), (version, count))
    return count

  return db.run_in_transaction(tx)

get_entity_group_version() dapat menampilkan None untuk entity group yang belum pernah ditulis.

Versi entity group diperoleh dengan memanggil get() pada entity pseudo khusus yang berisi properti __version__. Lihat dokumentasi referensi tentang EntityGroup untuk detailnya.

Kueri metadata

Jika fungsi bantuan yang dijelaskan di bagian sebelumnya tidak memenuhi kebutuhan, Anda dapat mengeluarkan permintaan metadata yang lebih mendetail atau fleksibel dengan kueri metadata eksplisit. Di Python, class model untuk kueri semacam itu ditentukan dalam paket google.appengine.ext.db.metadata. Model ini menyediakan jenis entity khusus yang dicadangkan untuk kueri metadata:

Class model Jenis entity
Namespace __namespace__
Kind __kind__
Property __property__

Model dan jenis ini tidak akan bertentangan dengan model dan jenis lain dengan nama yang sama yang mungkin sudah ada di aplikasi Anda. Dengan membuat kueri jenis khusus ini, Anda dapat mengambil entity yang berisi metadata yang diinginkan.

Entity yang ditampilkan oleh kueri metadata dibuat secara dinamis, berdasarkan status Datastore saat ini. Meskipun Anda dapat membuat instance lokal dari class model Namespace .Kind , atauProperty, setiap upaya untuk menyimpannya di Datastore akan gagal dengan pengecualian BadRequestError.

Anda dapat menerbitkan kueri metadata menggunakan objek kueri yang termasuk dalam salah satu dari dua class:

  • Objek Query yang ditampilkan oleh metode class Namespace.all(), Kind.all(), atau Property.all() (diwarisi dari metode superclass Model.all())
  • Objek GqlQuery untuk kueri bergaya GQL

Contoh berikut menampilkan nama semua jenis entity dalam aplikasi:

from google.appengine.ext import db
from google.appengine.ext.db.metadata import Kind

for k in Kind.all():
  print "kind: '%s'" % k.kind_name

Kueri namespace

Jika aplikasi Anda menggunakan Namespaces API, Anda dapat menggunakan kueri namespace untuk menemukan semua namespace yang digunakan dalam entity aplikasi. Dengan begitu, Anda dapat melakukan aktivitas seperti fungsi administratif di beberapa namespace.

Kueri namespace menampilkan entity __namespace__ jenis khusus yang nama kuncinya adalah nama namespace. (Pengecualiannya adalah namespace default yang ditetapkan oleh string kosong "": karena string kosong bukan nama kunci yang valid, namespace ini dikunci dengan ID numerik 1.) Kueri jenis ini hanya mendukung pemfilteran untuk rentang pada properti pseudo khusus __key__, yang nilainya adalah kunci entity. Hasilnya dapat diurutkan berdasarkan nilai __key__ menaik (tetapi tidak menurun). Karena entity __namespace__ tidak memiliki properti, kueri khusus kunci dan non-kunci menampilkan informasi yang sama.

Entity namespace adalah instance class model google.appengine.ext.db.metadata.Namespace. Properti string namespace_name, yang dihitung dari kunci entity, menampilkan nama namespace yang sesuai. (Jika kunci memiliki ID numerik 1, properti akan menampilkan string kosong.) Untuk memfasilitasi pembuatan kueri, model Namespace menyediakan metode class berikut:

Sebagai contoh, berikut adalah penerapan fungsi bantuan get_namespaces(), yang menampilkan daftar berisi nama semua namespace aplikasi (atau namespace yang berada dalam rentang antara dua nama yang ditentukan, start dan padaend ):

from google.appengine.ext import db
from google.appengine.ext.db.metadata import Namespace

def get_namespaces(start=None, end=None):

  # Start with unrestricted namespace query
  q = Namespace.all()

  # Limit to specified range, if any
  if start is not None:
    q.filter('__key__ >=', Namespace.key_for_namespace(start))
  if end is not None:
    q.filter('__key__ <', Namespace.key_for_namespace(end))

  # Return list of query results
  return [ns.namespace_name for ns in q]

Kueri jenis

Kueri jenis menampilkan entity jenis __kind__ yang nama kuncinya adalah nama jenis entity. Kueri jenis ini secara implisit dibatasi untuk namespace saat ini dan hanya mendukung pemfilteran untuk rentang melalui properti pseudo __key__. Hasilnya dapat diurutkan berdasarkan nilai __key__ menaik (tetapi tidak menurun). Karena entity __kind__ tidak memiliki properti, kueri khusus kunci dan non-kunci menampilkan informasi yang sama.

Entity jenis adalah instance dari class model google.appengine.ext.db.metadata.Kind. Properti string kind_name, yang dihitung dari kunci entity, menampilkan nama jenis entity yang sesuai. Untuk memfasilitasi pembuatan kueri, model Kind menyediakan metode class berikut:

Sebagai contoh, berikut adalah penerapan fungsi bantuan get_kinds(), yang menampilkan daftar berisi nama semua jenis entity aplikasi (atau yang berada dalam rentang antara dua nama yang ditentukan, start dan padaend ):

from google.appengine.ext import db
from google.appengine.ext.db.metadata import Kind

def get_kinds(start=None, end=None):

  # Start with unrestricted kind query
  q = Kind.all()

  # Limit to specified range, if any
  if start is not None and start != '':
    q.filter('__key__ >=', Kind.key_for_kind(start))
  if end is not None:
    if end == '':
      return []        # Empty string is not a valid kind name, so can't filter
    q.filter('__key__ <', Kind.key_for_kind(end))

  # Return list of query results
  return [k.kind_name for k in q]

Contoh berikut mencetak semua jenis yang namanya diawali dengan huruf kecil:

from google.appengine.ext import db
from google.appengine.ext.db.metadata import Kind

# Start with unrestricted kind query
q = Kind.all()

# Limit to lowercase initial letters
q.filter('__key__ >=', Kind.key_for_kind('a'))
endChar = chr(ord('z') + 1)                        # Character after 'z'
q.filter('__key__ <', Kind.key_for_kind(endChar))

# Print query results
for k in q:
  print k.kind_name

Kueri properti

Kueri properti menampilkan entity jenis __property__ yang menunjukkan properti yang terkait dengan jenis entity (terlepas dari apakah properti tersebut saat ini ditentukan dalam model jenis atau tidak). Entity yang mewakili properti P jenis K dibuat sebagai berikut:

  • Kunci entity memiliki jenis __property__ dan nama kunci P.
  • Kunci parent entity memiliki jenis __kind__ dan nama kunci K.

Entity properti adalah instance dari class model google.appengine.ext.db.metadata.Property. Properti string kind_name dan property_name, yang dihitung dari kunci entity, menampilkan nama jenis dan properti yang sesuai. Model Property menyediakan empat metode class untuk menyederhanakan pembuatan dan pemeriksaan kunci __property__:

Contoh berikut mengilustrasikan metode ini:

from google.appengine.ext import db
from google.appengine.ext.db.metadata import Property

class Employee(db.Model):
  name = db.StringProperty()
  ssn = db.IntegerProperty()

employee_key = Property.key_for_kind("Employee")
employee_name_key = Property.key_for_property("Employee", "Name")

Property.key_to_kind(employee_key)           # Returns "Employee"
Property.key_to_property(employee_name_key)  # Returns "Name"

Perilaku kueri properti bergantung pada apakah kueri tersebut khusus kunci atau khusus non-kunci (representasi properti), seperti yang dijelaskan di subbagian di bawah.

Kueri properti: khusus kunci

Kueri properti khusus kunci menampilkan kunci untuk setiap properti terindeks dari jenis entity yang ditentukan. (Properti yang tidak diindeks tidak disertakan.) Contoh berikut mencetak nama semua jenis entity aplikasi dan properti yang terkait dengan masing-masing jenis entity tersebut:

from google.appengine.ext import db
from google.appengine.ext.db.metadata import Property

# Create unrestricted keys-only property query
q = Property.all(keys_only=True)

# Print query results
for p in q:
  print "%s: %s" % (Property.key_to_kind(p), Property.key_to_property(p))

Kueri jenis ini secara implisit dibatasi untuk namespace saat ini dan mendukung pemfilteran hanya untuk rentang melalui properti pseudo __key__, dengan kunci menunjukkan entity __kind__ atau __property__. Hasilnya dapat diurutkan berdasarkan nilai __key__ menaik (tetapi tidak menurun). Pemfilteran diterapkan pada pasangan jenis properti, yang diurutkan pertama berdasarkan jenis dan kedua berdasarkan properti: misalnya, Anda memiliki entity dengan properti berikut:

  • jenis Account dengan properti
    • balance
    • company
  • jenis Employee dengan properti
    • name
    • ssn
  • jenis Invoice dengan properti
    • date
    • amount
  • jenis Manager dengan properti
    • name
    • title
  • jenis Product dengan properti
    • description
    • price

Kueri untuk menampilkan data properti akan terlihat seperti ini:

from google.appengine.ext import db
from google.appengine.ext.db.metadata import Property

# Start with unrestricted keys-only property query
q = Property.all(keys_only=True)

# Limit range
q.filter('__key__ >=', Property.key_for_property("Employee", "salary"))
q.filter('__key__ <=', Property.key_for_property("Manager", "salary"))

# Print query results
for p in q:
  print "%s: %s" % (Property.key_to_kind(p), Property.key_to_property(p))

Kueri di atas akan menampilkan hal berikut:

Employee: ssn
Invoice: date
Invoice: amount
Manager: name

Perhatikan bahwa hasilnya tidak menyertakan properti name dari jenis Employee dan properti title dari jenis Manager, maupun properti apa pun dengan jenis Account dan Product, karena berada di luar rentang yang ditetapkan untuk kueri ini.

Kueri properti juga mendukung pemfilteran ancestor pada kunci __kind__ atau __property__, untuk membatasi hasil kueri ke satu jenis atau properti. Anda dapat menggunakannya, misalnya, untuk mendapatkan properti yang terkait dengan jenis entity tertentu, seperti dalam contoh berikut:

(penerapan fungsi bantuan get_properties_of_kind())

from google.appengine.ext import db
from google.appengine.ext.db.metadata import Property

def get_properties_of_kind(kind, start=None, end=None):

  # Start with unrestricted keys-only property query
  q = Property.all(keys_only=True)

  # Limit to specified kind
  q.ancestor(Property.key_for_kind(kind))

  # Limit to specified range, if any
  if start is not None and start != '':
    q.filter('__key__ >=', Property.key_for_property(kind, start))
  if end is not None:
    if end == '':
      return []     # Empty string is not a valid property name, so can't filter
    q.filter('__key__ <', Property.key_for_property(kind, end))

  # Return list of query results
  return [Property.key_to_property(p) for p in q]

Kueri properti: khusus non-kunci (representasi properti)

Kueri properti khusus non-kunci, yang dikenal sebagai kueri representasi properti, menampilkan informasi tambahan tentang representasi yang digunakan oleh setiap pasangan jenis properti. (Properti yang tidak diindeks tidak disertakan.) Entity yang ditampilkan untuk properti P sejenis K memiliki kunci yang sama dengan kueri khusus kunci terkait, serta properti property_representation tambahan yang menampilkan representasi properti. Nilai properti ini adalah class instance StringListProperty yang berisi satu string untuk setiap representasi properti P yang ditemukan dalam entity jenis K.

Perhatikan bahwa representasi tidak sama dengan class properti; beberapa class properti dapat dipetakan ke representasi yang sama. (Misalnya, StringProperty dan PhoneNumberProperty sama-sama menggunakan representasi STRING.)

Tabel berikut dipetakan dari class properti ke representasinya:

Class properti Representasi
IntegerProperty INT64
FloatProperty DOUBLE
BooleanProperty BOOLEAN
StringProperty STRING
ByteStringProperty STRING
DateProperty INT64
TimeProperty INT64
DateTimeProperty INT64
GeoPtProperty POINT
PostalAddressProperty STRING
PhoneNumberProperty STRING
EmailProperty STRING
UserProperty USER
IMProperty STRING
LinkProperty STRING
CategoryProperty STRING
RatingProperty INT64
ReferenceProperty
SelfReferenceProperty
REFERENCE
blobstore.BlobReferenceProperty STRING
ListProperty Representasi elemen daftar
StringListProperty Representasi elemen daftar

Sebagai contoh, berikut adalah penerapan fungsi bantuan get_representations_of_kind(), yang menampilkan kamus yang berisi representasi untuk semua properti yang diindeks oleh aplikasi (atau properti tersebut dalam rentang antara dua nama yang ditentukan, start dan end) yang terkait dengan jenis entity tertentu. Kamus memetakan nama setiap properti ke daftar representasi properti tersebut:

from google.appengine.ext import db
from google.appengine.ext.db.metadata import Property

def get_representations_of_kind(kind, start=None, end=None):

  # Start with unrestricted non-keys-only property query
  q = Property.all()

  # Limit to specified kind
  q.ancestor(Property.key_for_kind(kind))

  # Limit to specified range, if any
  if start is not None and start != '':
    q.filter('__key__ >=', Property.key_for_property(kind, start))
  if end is not None:
    if end == '':
      return []     # Empty string is not a valid property name, so can't filter
    q.filter('__key__ <', Property.key_for_property(kind, end))

  # Initialize result dictionary
  result = {}

  # Add query results to dictionary
  for p in q:
    result[p.property_name] = p.property_representation

  # Return dictionary
  return result