エンティティ プロパティ リファレンス

Datastore では、プロパティ値でさまざまなデータ型がサポートされています。主なものを次に紹介します。

  • 整数
  • 浮動小数点数
  • 文字列
  • 日付
  • バイナリデータ

すべての型の一覧は、プロパティと値の型をご覧ください。

プロパティと値の型

エンティティに関連付けられたデータ値は 1 つ以上のプロパティで構成されます。各プロパティには名前と 1 つ以上の値があります。プロパティは異なる型の複数の値を持つことができるため、2 つのエンティティの同じプロパティに異なる型の値が存在する場合もあります。プロパティはインデックス付けされている場合とされていない場合があります(プロパティ P で並べ替えまたはフィルタリングを行うクエリでは、P がインデックス付けされていないエンティティは無視されます)。1 つのエンティティに、インデックスが付けられたプロパティを最大 20,000 個まで割り当てることができます。

サポートされている値の型は、次のとおりです。

型が混合した値を持つプロパティをクエリで扱う場合、Datastore では内部表現に基づく決定論的な順序付けが使用されます。

  1. Null 値
  2. 固定小数点数
    • 整数
    • 日時型
  3. ブール値
  4. バイト列
    • Unicode 文字列
    • Blobstore のキー
  5. 浮動小数点数
  6. Datastore のキー

長いテキスト文字列と長いバイト文字列はインデックスに登録されないため、順序付けは定義されていません。

プロパティ型

NDB は次のプロパティ型をサポートしています。

プロパティ型 説明
IntegerProperty 64 ビット符号付き整数
FloatProperty 倍精度浮動小数点数
BooleanProperty ブール値
StringProperty Unicode 文字列。最大 1500 バイトで、インデックス付きです。
TextProperty Unicode 文字列。長さは無制限で、インデックスなしです。
BlobProperty 解釈されないバイト文字列:
indexed=True の場合、最大 1,500 バイトで、インデックス付きです。
indexedFalse(デフォルト)の場合、長さは無制限で、インデックスなしです。
オプションのキーワード引数: compressed
DateTimeProperty 日付および時刻(日付および時刻プロパティを参照)
DateProperty 日付(日付および時刻プロパティを参照)
TimeProperty 時刻(日付および時刻プロパティを参照)
GeoPtProperty 地理的場所。これは ndb.GeoPt オブジェクトです。このオブジェクトの属性 latlon はどちらも浮動小数点数です。次のような 2 つの浮動小数点数(例: ndb.GeoPt(52.37, 4.88))、または文字列(例: ndb.GeoPt("52.37, 4.88"))を使用して生成できます。(実際にはこれは db.GeoPt
KeyProperty データストアのキー
オプションのキーワード引数: kind=kind。このプロパティに割り当てられたキーは、常に指定した種類であることが必要です。文字列または Model サブクラスにすることもできます。
BlobKeyProperty Blobstore のキー
古いデータベース API の BlobReferenceProperty に対応しますが、プロパティ値は BlobInfo ではなく BlobKey です。これから BlobInfo(blobkey) を使って BlobInfo を生成できます。
UserProperty ユーザー オブジェクト
StructuredProperty ある種類のモデルを値によって別の種類のモデルに含めます(構造化プロパティを参照)。
LocalStructuredProperty StructuredProperty に似ていますが、ディスク上の表現は不透明な blob で、インデックスに登録されません(構造化プロパティを参照)。
オプションのキーワード引数: compressed
JsonProperty 値は Python オブジェクト(リスト、辞書、文字列など)で、Python の json モジュールを使ってシリアル化できます。Datastore は JSON シリアル化を blob として格納します。デフォルトでは、インデックスは付きません。
オプションのキーワード引数: compressed
PickleProperty 値は Python オブジェクト(リスト、辞書、文字列など)で、Python の pickle プロトコルを使ってシリアル化できます。Datastore は pickle シリアル化を blob として格納します。デフォルトでは、インデックスは付きません。
オプションのキーワード引数: compressed
GenericProperty 汎用値
ほとんどの場合は Expando クラスで使用されますが、明示的にも使用できます。intlongfloatboolstrunicodedatetimeKeyBlobKeyGeoPtUserNone のいずれかの型になります。
ComputedProperty ユーザー定義関数によって他のプロパティから計算される値 (計算済みプロパティを参照)。

これらのプロパティの一部にはオプションのキーワード引数 compressed があります。プロパティが compressed=True になっている場合は、そのデータがディスク上で gzip を使って圧縮されます。占有する領域は少なくて済みますが、書き込み操作や読み取りオペレーションでのエンコード / デコードに CPU 時間が必要になります。

圧縮と解凍はどちらも「消極的に」行われます。圧縮されたプロパティ値は初めてアクセスされたときに解凍されます。圧縮済みのプロパティ値が含まれているエンティティを読み取り、圧縮済みのプロパティにアクセスしないまま書き戻した場合は、解凍も圧縮もまったく行われません。インコンテキスト キャッシュもこの消極的なスキーマに関与しますが、Memcache は常に圧縮済みプロパティの圧縮済みの値を格納します。

圧縮のために余分な CPU 時間が必要になるため、通常はデータが大きすぎて圧縮しなければ収まらない場合にのみ、圧縮済みのプロパティを使うことをおすすめします。画像やその他のメディアデータの場合は、すでにメディア固有の圧縮アルゴリズム(たとえば画像の場合は JPEG など)を使って圧縮されているため、gzip で圧縮してもあまり効果がないことを覚えておいてください。

プロパティ オプション

ほとんどのプロパティ型はいくつかの標準引数をサポートしています。1 つ目は、プロパティの Datastore 名を指定するオプションの場所引数です。これを使用すると、Datastore で使用するプロパティに、アプリケーションの視点で別の名前を付けることができます。このような名前は、Datastore の領域を減らすためによく使用されます。Datastore ではプロパティの短縮名を使用し、コードではもっと長くてわかりやすい名前を使用できます。次に例を示します。

class Employee(ndb.Model):
    full_name = ndb.StringProperty('n')
    retirement_age = ndb.IntegerProperty('r')

特に、エンティティごとに多くの値が使用されることが想定される反復プロパティを使う場合に便利です。

また、ほとんどのプロパティ型は次のキーワード引数をサポートしています。

引数 デフォルト説明
indexed bool 通常は Trueデータストアのインデックスにプロパティを含めます。False の場合、値をクエリすることはできませんが、書き込みは速くなります。すべてのプロパティ型がインデックス生成をサポートしているとは限らず、そうしたプロパティ型で indexedTrue に設定すると失敗します。
インデックスなしのプロパティは、インデックス付きのプロパティと比べて、書き込み操作のコストが少なくなります。
repeated bool False プロパティ値は、基になる型の値が格納される Python リストです(反復プロパティを参照)。
required=True または default=True と組み合わせることはできません。
required bool False プロパティに値を指定しておく必要があります。
default プロパティの基になる型なし何も明示的に指定しない場合のプロパティのデフォルト値。
choices 基になる型の値のリストNone オプションの許容値リストです。
validator 関数None

値を検証し(通常は)強制するためのオプションの関数。

引数(propvalue)を使用して呼び出され、値(強制変換される場合がある)を返します。値が返されない場合は例外が発生します。強制変換された値に対して再度この関数を呼び出すときに、値がさらに変更されることはないはずです(たとえば、value.strip()value.lower() を返すのは問題ありませんが、value + '$' を返すのは誤りです)。None を返す場合もあります。これは「変更なし」を意味します。プロパティのサブクラスの作成もご覧ください。

verbose_name 文字列None

jinja2 などのウェブ フォーム フレームワークで使うオプションの HTML ラベルです。

反復プロパティ

repeated=True が指定されたプロパティはすべて反復プロパティになります。このプロパティは、1 つの値ではなく、基になる型の値のリストの形式を取ります。たとえば、IntegerProperty(repeated=True) で定義されたプロパティの値は整数のリストです。

Datastore ではこのようなプロパティに対して複数の値が表示される場合があります。値ごとに別々のインデックス レコードが作成されます。これはクエリのセマンティクスに影響を与えます。例については、反復プロパティのクエリを実行するをご覧ください。

次の例では反復プロパティを使用しています。

class Article(ndb.Model):
    title = ndb.StringProperty()
    stars = ndb.IntegerProperty()
    tags = ndb.StringProperty(repeated=True)
...
article = Article(
    title='Python versus Ruby',
    stars=3,
    tags=['python', 'ruby'])
article.put()

このコードは、次の内容の Datastore エンティティを作成します。

assert article.title == 'Python versus Ruby'
assert article.stars == 3
assert sorted(article.tags) == sorted(['python', 'ruby'])

tags プロパティのクエリを実行する場合、このエンティティが 'python''ruby' のどちらかのクエリ条件を満たします。

反復プロパティを更新する場合は、新しいリストを割り当てるか、既存のリストを変更できます。新しいリストを割り当てた場合は、リスト項目の型が即座に検証されます。項目の型が無効な場合(たとえば、上で [1, 2]art.tags に代入した場合)は例外が発生します。リストを変更した場合、変更が即座に検証されることはありません。代わりに、エンティティを Datastore に書き込んだときに値が検証されます。

Datastore では反復プロパティのリスト項目の順序が保持されるので、それらの順序に対してなんらかの意味を持たせることができます。

日付および時刻プロパティ

日付関連の値と時刻関連の値を格納するために、次の 3 つのプロパティ型を使用できます。

  • DateProperty
  • TimeProperty
  • DateTimeProperty

これらは、標準の Python datetime モジュールの対応するクラス(datetimedatetime)に属する値を取ります。この 3 つのうち最も一般的なものが DateTimeProperty で、暦の日付と時計の時刻の両方を表します。それ以外のものは、日付のみ(誕生日など)または時刻のみ(ミーティング時刻など)を必要とする特殊な場合に役立つことがあります。技術上の理由から、DatePropertyTimePropertyDateTimeProperty のサブクラスになっていますが、この継承関係に頼ることは避けてください(モジュール datetime 自体によって定義される基になるクラス間の継承関係とは異なることに注意してください)。

注: App Engine の時刻は常に UTC(協定世界時)で表されます。これが関係するのは、現在の日付または時刻(datetime.datetime.now())を値として使う場合や、datetime オブジェクトを POSIX タイムスタンプまたはタイムタプルに変換する場合、またはその逆の変換を行う場合です。しかし、Datastore にはタイムゾーン情報が明示的に格納されることはないので、現在の時刻を使用する場合や変換を行う場合は、タイムゾーンの問題を注意深く処理できるようであれば、ローカル時刻を表すように変換することもできます。

これらのプロパティにはそれぞれ、さらに 2 つのブール値のキーワード オプションがあります。

オプション 説明
auto_now_add エンティティの作成時に、プロパティを現在の日付 / 時刻に設定します。このプロパティは手動でオーバーライドできます。エンティティが更新されても、プロパティは変化しません。その場合は auto_now を使用します。
auto_now エンティティの作成時、およびエンティティが更新されるたびに、プロパティを現在の日付 / 時刻に設定します。

これらのオプションを repeated=True と組み合わせることはできません。どちらもデフォルトは False です。両方を True に設定した場合は、auto_now が優先されます。プロパティの値を auto_now_add=True でオーバーライドすることはできますが、auto_now=True でオーバーライドすることはできません。エンティティが書き込まれるまで、自動値は生成されません。つまり、これらのオプションでは動的なデフォルトは提供されません(この詳細は古いデータベース API とは異なります)。

注: auto_now_add=True でプロパティを書き込むトランザクションが失敗し、後で再試行される場合は、元の書き込みと同じ時間値が再度使用され、再試行時の時間には更新されません。トランザクションが恒久的に失敗する場合でも、プロパティの値はエンティティのメモリ内コピーに設定されたままになります。

構造化プロパティ

モデルのプロパティを構造化できます。たとえば、住所のリストを格納するモデルクラス Contact を定義し、それぞれに内部構造を持たせることができます。構造化プロパティ(StructuredProperty 型)では、たとえば次のようなことが可能です。

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)
...
guido = Contact(
    name='Guido',
    addresses=[
        Address(
            type='home',
            city='Amsterdam'),
        Address(
            type='work',
            street='Spear St',
            city='SF')])

guido.put()

このコードは、次のプロパティを持つ Datastore エンティティを 1 つ作成します。

assert guido.name == 'Guido'
addresses = guido.addresses
assert addresses[0].type == 'home'
assert addresses[1].type == 'work'
assert addresses[0].street is None
assert addresses[1].street == 'Spear St'
assert addresses[0].city == 'Amsterdam'
assert addresses[1].city == 'SF'

このようなエンティティを読み戻すと、元のエンティティ Contact がまったく同じものに再構築されます。Address インスタンスはモデルクラスの場合と同じ構文を使って定義されていますが、完全なエンティティではなく、固有のキーが Datastore に存在しません。これらのインスタンスを、所属先の Contact エンティティとは別に取得することはできません。ただし、アプリケーションでそれらの個々のフィールドの値をクエリすることはできます。構造化プロパティ値のフィルタ処理をご覧ください。address.typeaddress.streetaddress.city は、Datastore の視点では並列配列として処理されますが、NDB ライブラリではそうした側面は無視して、Address インスタンスの対応するリストが作成されます。

構造化プロパティには通常のプロパティ オプションを指定できます(indexed を除く)。この場合は、Datastore 名が 2 つ目の場所引数になります(1 つ目の引数は、サブ構造体の定義に使われるモデルクラスです)。

サブ構造体の内部プロパティをクエリする必要がない場合は、代わりに、ローカルの構造化プロパティ(LocalStructuredProperty)を使用できます。前述の例で StructuredPropertyLocalStructuredProperty に置き換えた場合、Python コードの動作は同じですが、Datastore からは各アドレスの不透明な blob しか見えません。この例で作成される guido エンティティは次のように格納されます。 name = 'Guido' address = <opaque blob for {'type': 'home', 'city': 'Amsterdam'}> address = <opaque blob for {'type': 'work', 'city': 'SF', 'street': 'Spear St'}>

エンティティは正しく読み戻されます。この型のプロパティは、常にインデックスが付かないため、アドレス値のクエリを実行することができません。

注: 構造化されているかどうかにかかわらず、プロパティがネストされている StructuredProperty は、反復プロパティの 1 つのレイヤだけをサポートします。StructuredProperty を反復することも、ネストされたプロパティを反復することもできますが、両方を反復することはできません。この回避策として、こうした制約のない LocalStructuredProperty を使用できます(ただし、そのプロパティ値に対してクエリを実行することはできません)。

計算済みプロパティ

計算済みプロパティ(ComputedProperty)は、アプリケーションから提供される関数によって値が他のプロパティ値から計算される読み取り専用プロパティです。計算済みプロパティは、一般的なプロパティでサポートされている型しかサポートしないことに注意してください。計算された値は、Datastore ビューアでクエリ実行や表示ができるように Datastore に書き込まれますが、エンティティが Datastore から読み戻された場合は、格納されていた値が無視されます。代わりに、値が要求されるたびにこの関数が呼び出されて値の再計算が行われます。次に例を示します。

class SomeEntity(ndb.Model):
    name = ndb.StringProperty()
    name_lower = ndb.ComputedProperty(lambda self: self.name.lower())
...
entity = SomeEntity(name='Nick')
entity.put()

このコードは、次のプロパティ値を持つエンティティを格納します。

assert entity.name == 'Nick'
assert entity.name_lower == 'nick'

名前を「Nickie」に変更して name_lower の値を問い合わせると、「nickie」が返されます。

entity.name = 'Nick'
assert entity.name_lower == 'nick'
entity.name = 'Nickie'
assert entity.name_lower == 'nickie'

注: ComputedProperty は、アプリケーションで計算済みの値をクエリする場合に使用します。Python コードの派生版を使用するだけの場合は、通常のメソッドを定義するか、Python の @property ビルトインを使用します。

注: モデルを作成するときに手動でキーを指定するのではなく、Datastore に依存してエンティティの ID の自動生成する場合、最初の put()ComputedProperty は ID フィールドを読み取れません。これは、ID の生成る前に ID フィールドが計算されるためです。エンティティの ID を使用する ComputedProperty が必要な場合は、allocate_ids メソッドでエンティティ作成用の ID とキーを生成できます。これにより、ComputedProperty はエンティティの最初の put() でその ID を参照できます。

Google Protocol RPC メッセージのプロパティ

Google Protocol RPC ライブラリでは、構造化データに Message オブジェクトが使用され、RPC のリクエストやレスポンスなどを表現できます。NDB では、Google Protocol RPC Message オブジェクトをエンティティのプロパティとして格納するための API が提供されます。次のような Message サブクラスを定義するとします。

from protorpc import messages
...
class Note(messages.Message):
    text = messages.StringField(1, required=True)
    when = messages.IntegerField(2)

NDB の msgprop API を使用して、Note オブジェクトをエンティティ プロパティ値として Datastore に格納できます。

from google.appengine.ext import ndb
from google.appengine.ext.ndb import msgprop
...
class NoteStore(ndb.Model):
    note = msgprop.MessageProperty(Note, indexed_fields=['when'])
    name = ndb.StringProperty()
...
my_note = Note(text='Excellent note', when=50)

ns = NoteStore(note=my_note, name='excellent')
key = ns.put()

new_notes = NoteStore.query(NoteStore.note.when >= 10).fetch()

フィールド名のクエリを実行するには、フィールド名にインデックスを付ける必要があります。indexed_fields パラメータでインデックスを付けるフィールド名のリストを MessageProperty に指定できます。

MessageProperty では多くのプロパティ オプション(すべてではありません)がサポートされています。サポートされているオプションは次のとおりです。

  • name
  • repeated
  • required
  • default
  • choices
  • validator
  • verbose_name

Message プロパティは、indexed プロパティ オプションをサポートしません。Message 値にインデックスを付けることはできません(前述のようにメッセージのフィールドにインデックスを付けることはできます)。

ネストされたメッセージ(MessageField を使用)も使用できます。

class Notebook(messages.Message):
    notes = messages.MessageField(Note, 1, repeated=True)
...
class SignedStorableNotebook(ndb.Model):
    author = ndb.StringProperty()
    nb = msgprop.MessageProperty(
        Notebook, indexed_fields=['notes.text', 'notes.when'])

MessageProperty には、protocol という特別なプロパティ オプションがあります。このオプションでは、メッセージ オブジェクトが Datastore にシリアル化される方法を指定します。値は、protorpc.remote.Protocols クラスで使用されるプロトコル名です。サポートされているプロトコル名は protobufprotojson で、デフォルトは protobuf です。

msgpropEnumProperty も定義します。これは、protorpc.messages.Enum の値をエンティティに格納するために使用可能なプロパティ型です。次に例を示します。

class Color(messages.Enum):
    RED = 620
    GREEN = 495
    BLUE = 450
...
class Part(ndb.Model):
    name = ndb.StringProperty()
    color = msgprop.EnumProperty(Color, required=True)
...
p1 = Part(name='foo', color=Color.RED)
print p1.color  # prints "RED"

EnumProperty には値が整数として格納されます。実際、EnumPropertyIntegerProperty のサブクラスです。したがって、すでに格納されているエンティティを変更せずに列挙値の名前を変更できますが、番号の付け直しはできません。

EnumProperty は、次のプロパティ オプションをサポートします。

  • name
  • indexed
  • repeated
  • required
  • default
  • choices
  • validator
  • verbose_name

NDB エンティティ モデルについて

NDB エンティティ モデルではプロパティを定義できます。エンティティのプロパティは、データを保持するための構造化された方法である Python のクラスのデータメンバーや、データベース スキーマ内のフィールドに少し似ています。

通常のアプリケーションでは、いくつかのプロパティ クラス属性を使って Model から継承したクラスを定義することでデータモデルを定義します。次に例を示します。


from google.appengine.ext import ndb
...
class Account(ndb.Model):
    username = ndb.StringProperty()
    userid = ndb.IntegerProperty()
    email = ndb.StringProperty()

ここで、usernameuseridemailAccount のプロパティです。

他にもいくつかのプロパティ型があります。日付や時刻の表現に役立つものや、便利な自動更新機能を持つものがあります。

アプリケーションでは、プロパティ オプションを指定してプロパティの動作をカスタマイズできます。これを利用して、検証の簡素化、デフォルトの設定、クエリ インデックスの生成の変更を行うことができます。

モデルには、より複雑なプロパティを設定できます。反復プロパティはリストに似ています。構造化プロパティはオブジェクトに似ています。読み取り専用の計算済みプロパティは関数で定義します。そのため、1 つ以上の他のプロパティに基づくプロパティを簡単に定義できます。Expando モデルではプロパティを動的に定義できます。