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

Datastore モードの Firestore(Datastore)では、プロパティ値にさまざまなデータ型がサポートされています。サポートしているデータ型の例を次に示します。

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

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

プロパティと値の型

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

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

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

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

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

プロパティ型

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

プロパティ型 説明
IntegerProperty 64 ビット符号付き整数
FloatProperty 倍精度浮動小数点数
BooleanProperty ブール値
StringProperty Unicode 文字列。最大 1,500 バイトで、インデックス付き
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 値を検証し(通常は)強制するためのオプションの関数。 引数 (prop, value) を使用して呼び出され、値(強制変換される場合がある)を返します。値が返されない場合は例外が発生します。強制変換された値に対して再度この関数を呼び出すときに、値がさらに変更されることはないはずです(たとえば、value.strip()value.lower() を返すのは問題ありませんが、value + '$' を返すのは誤りです)。None を返す場合もあります。これは「変更なし」を意味します。プロパティのサブクラスの作成もご覧ください。
verbose_name string 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 自体によって定義される基になるクラス間の継承関係とは異なることに注意してください)。

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

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

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

構造化プロパティ

モデルのプロパティを構造化できます。 たとえば、住所のリストを格納するモデルクラス 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'}>

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

計算済みプロパティ

計算済みプロパティ(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'

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 モデルではプロパティを動的に定義できます。