Datastore モードの Firestore(Datastore)では、プロパティ値にさまざまなデータ型がサポートされています。サポートしているデータ型の例を次に示します。
- 整数
- 浮動小数点数
- 文字列
- 日付
- バイナリデータ
すべての型の一覧は、プロパティと値の型をご覧ください。
プロパティと値の型
エンティティに関連付けられたデータ値は 1 つ以上のプロパティで構成されます。各プロパティには名前と 1 つ以上の値があります。プロパティは異なる型の複数の値を持つことができるため、2 つのエンティティの同じプロパティに異なる型の値が存在する場合もあります。プロパティはインデックス付けされている場合とされていない場合があります(プロパティ P で並べ替えまたはフィルタリングを行うクエリでは、P がインデックス付けされていないエンティティは無視されます)。1 つのエンティティに、インデックスが付けられたプロパティを最大 20,000 個まで割り当てることができます。
型が混合した値を持つプロパティをクエリで扱う場合、Datastore では内部表現に基づく決定論的な順序付けが使用されます。
- Null 値
- 固定小数点数
- 整数
- 日時型
- ブール値
- バイト列
- Unicode 文字列
- Blobstore のキー
- 浮動小数点数
- Datastore のキー
長いテキスト文字列と長いバイト文字列はインデックスに登録されないため、順序付けは定義されていません。
プロパティ型
NDB は次のプロパティ型をサポートしています。
プロパティ型 | 説明 |
---|---|
IntegerProperty | 64 ビット符号付き整数 |
FloatProperty | 倍精度浮動小数点数 |
BooleanProperty | ブール値 |
StringProperty | Unicode 文字列。最大 1500 バイトで、インデックス付きです。 |
TextProperty | Unicode 文字列。長さは無制限で、インデックスなしです。 |
BlobProperty | 解釈されないバイト文字列:indexed=True の場合、最大 1,500 バイトで、インデックス付きです。indexed が False (デフォルト)の場合、長さは無制限で、インデックスなしです。オプションのキーワード引数: compressed 。 |
DateTimeProperty
| 日付および時刻(日付および時刻プロパティを参照) |
DateProperty
| 日付(日付および時刻プロパティを参照) |
TimeProperty
| 時刻(日付および時刻プロパティを参照) |
GeoPtProperty
| 地理的場所。これは ndb.GeoPt オブジェクトです。このオブジェクトの属性 lat と lon はどちらも浮動小数点数です。次のような 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 クラスで使用されますが、明示的にも使用できます。int 、long 、float 、bool 、str 、unicode 、datetime 、Key 、BlobKey 、GeoPt 、User 、None のいずれかの型になります。 |
ComputedProperty
| ユーザー定義関数によって他のプロパティから計算される値 (計算済みプロパティを参照)。 |
これらのプロパティの一部にはオプションのキーワード引数 compressed
があります。プロパティが compressed=True
になっている場合は、そのデータがディスク上で gzip を使って圧縮されます。占有する領域は少なくて済みますが、書き込み操作や読み取りオペレーションでのエンコード / デコードに CPU 時間が必要になります。
圧縮と解凍はどちらも「消極的に」行われます。圧縮されたプロパティ値は初めてアクセスされたときに解凍されます。圧縮済みのプロパティ値が含まれているエンティティを読み取り、圧縮済みのプロパティにアクセスしないまま書き戻した場合は、解凍も圧縮もまったく行われません。インコンテキスト キャッシュもこの消極的なスキーマに関与しますが、Memcache は常に圧縮済みプロパティの圧縮済みの値を格納します。
圧縮のために余分な CPU 時間が必要になるため、通常はデータが大きすぎて圧縮しなければ収まらない場合にのみ、圧縮済みのプロパティを使うことをおすすめします。画像やその他のメディアデータの場合は、すでにメディア固有の圧縮アルゴリズム(たとえば画像の場合は JPEG など)を使って圧縮されているため、gzip で圧縮してもあまり効果がないことを覚えておいてください。
プロパティ オプション
ほとんどのプロパティ型はいくつかの標準引数をサポートしています。1 つ目は、プロパティの Datastore 名を指定するオプションの場所引数です。これを使用すると、Datastore で使用するプロパティに、アプリケーションの視点で別の名前を付けることができます。このような名前は、Datastore の領域を減らすためによく使用されます。Datastore ではプロパティの短縮名を使用し、コードではもっと長くてわかりやすい名前を使用できます。次に例を示します。
特に、エンティティごとに多くの値が使用されることが想定される反復プロパティを使う場合に便利です。
また、ほとんどのプロパティ型は次のキーワード引数をサポートしています。
引数 | 型 | デフォルト | 説明 |
---|---|---|---|
indexed | bool | 通常は True | データストアのインデックスにプロパティを含めます。False の場合、値をクエリすることはできませんが、書き込みは速くなります。すべてのプロパティ型がインデックス生成をサポートしているとは限らず、そうしたプロパティ型で indexed を True に設定すると失敗します。インデックスなしのプロパティは、インデックス付きのプロパティと比べて、書き込み操作のコストが少なくなります。 |
repeated | bool | False | プロパティ値は、基になる型の値が格納される Python リストです(反復プロパティを参照)。required=True または default=True と組み合わせることはできません。 |
required | bool | False | プロパティに値を指定しておく必要があります。 |
default | プロパティの基になる型 | なし | 何も明示的に指定しない場合のプロパティのデフォルト値。 |
choices | 基になる型の値のリスト | None | オプションの許容値リストです。 |
validator | 関数 | None | 値を検証し(通常は)強制するためのオプションの関数。 引数(prop、value)を使用して呼び出され、値(強制変換される場合がある)を返します。値が返されない場合は例外が発生します。強制変換された値に対して再度この関数を呼び出すときに、値がさらに変更されることはないはずです(たとえば、 |
verbose_name | 文字列 | None
| jinja2 などのウェブ フォーム フレームワークで使うオプションの HTML ラベルです。 |
反復プロパティ
repeated=True
が指定されたプロパティはすべて反復プロパティになります。このプロパティは、1 つの値ではなく、基になる型の値のリストの形式を取ります。たとえば、IntegerProperty(repeated=True)
で定義されたプロパティの値は整数のリストです。
Datastore ではこのようなプロパティに対して複数の値が表示される場合があります。値ごとに別々のインデックス レコードが作成されます。これはクエリのセマンティクスに影響を与えます。例については、反復プロパティのクエリを実行するをご覧ください。
次の例では、反復プロパティを使用しています。
...
このコードは、次の内容の Datastore エンティティを作成します。
tags
プロパティのクエリを実行する場合、このエンティティが 'python'
と 'ruby'
のどちらかのクエリ条件を満たします。
反復プロパティを更新する場合は、新しいリストを割り当てるか、既存のリストを変更できます。新しいリストを割り当てた場合は、リスト項目の型が即座に検証されます。項目の型が無効な場合(たとえば、上で [1, 2]
を art.tags
に代入した場合)は例外が発生します。リストを変更した場合、変更が即座に検証されることはありません。代わりに、エンティティを Datastore に書き込んだときに値が検証されます。
Datastore では反復プロパティのリスト項目の順序が保持されるので、それらの順序に対してなんらかの意味を持たせることができます。
日付および時刻プロパティ
日付関連の値と時刻関連の値を格納するために、次の 3 つのプロパティ型を使用できます。
DateProperty
TimeProperty
DateTimeProperty
これらは、標準の Python datetime
モジュールの対応するクラス(date
、time
、datetime
)に属する値を取ります。この 3 つのうち最も一般的なものが DateTimeProperty
で、暦の日付と時計の時刻の両方を表します。それ以外のものは、日付のみ(誕生日など)または時刻のみ(ミーティング時刻など)を必要とする特殊な場合に役立つことがあります。技術上の理由から、DateProperty
と TimeProperty
は DateTimeProperty
のサブクラスになっていますが、この継承関係に頼ることは避けてください(モジュール 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
型)では、たとえば次のようなことが可能です。
...
...
このコードは、次のプロパティを持つ Datastore エンティティを 1 つ作成します。
このようなエンティティを読み戻すと、元のエンティティ Contact
がまったく同じものに再構築されます。Address
インスタンスはモデルクラスの場合と同じ構文を使って定義されていますが、完全なエンティティではなく、固有のキーが Datastore に存在しません。これらのインスタンスを、所属先の Contact
エンティティとは別に取得することはできません。ただし、アプリケーションでそれらの個々のフィールドの値をクエリすることはできます。構造化プロパティ値のフィルタ処理をご覧ください。address.type
、address.street
、address.city
は、Datastore の視点では並列配列として処理されますが、NDB ライブラリではそうした側面は無視して、Address
インスタンスの対応するリストが作成されます。
構造化プロパティには通常のプロパティ オプションを指定できます(indexed
を除く)。この場合は、Datastore 名が 2 つ目の場所引数になります(1 つ目の引数は、サブ構造体の定義に使われるモデルクラスです)。
サブ構造体の内部プロパティをクエリする必要がない場合は、代わりに、ローカルの構造化プロパティ(LocalStructuredProperty
)を使用できます。前述の例で StructuredProperty
を LocalStructuredProperty
に置き換えた場合、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 から読み戻された場合は、格納されていた値が無視されます。代わりに、値が要求されるたびにこの関数が呼び出されて値の再計算が行われます。次に例を示します。
...
このコードは、次のプロパティ値を持つエンティティを格納します。
名前を「Nickie」に変更して 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
サブクラスを定義するとします。
...
NDB の msgprop
API を使用して、Note
オブジェクトをエンティティ プロパティ値として Datastore に格納できます。
...
...
フィールド名のクエリを実行するには、フィールド名にインデックスを付ける必要があります。indexed_fields
パラメータでインデックスを付けるフィールド名のリストを MessageProperty
に指定できます。
MessageProperty
では多くのプロパティ オプション(すべてではありません)がサポートされています。サポートされているオプションは次のとおりです。
name
repeated
required
default
choices
validator
verbose_name
Message プロパティは、indexed
プロパティ オプションをサポートしません。Message
値にインデックスを付けることはできません(前述のようにメッセージのフィールドにインデックスを付けることはできます)。
ネストされたメッセージ(MessageField
を使用)も使用できます。
...
MessageProperty
には、protocol
という特別なプロパティ オプションがあります。このオプションでは、メッセージ オブジェクトが Datastore にシリアル化される方法を指定します。値は、protorpc.remote.Protocols
クラスで使用されるプロトコル名です。サポートされているプロトコル名は protobuf
と protojson
で、デフォルトは protobuf
です。
msgprop
は EnumProperty
も定義します。これは、protorpc.messages.Enum
の値をエンティティに格納するために使用可能なプロパティ型です。次に例を示します。
...
...
EnumProperty
には値が整数として格納されます。実際、EnumProperty
は IntegerProperty
のサブクラスです。したがって、すでに格納されているエンティティを変更せずに列挙値の名前を変更できますが、番号の付け直しはできません。
EnumProperty は、次のプロパティ オプションをサポートします。
name
indexed
repeated
required
default
choices
validator
verbose_name
NDB エンティティ モデルについて
NDB エンティティ モデルではプロパティを定義できます。エンティティのプロパティは、データを保持するための構造化された方法である Python のクラスのデータメンバーや、データベース スキーマ内のフィールドに少し似ています。
通常のアプリケーションでは、いくつかのプロパティ クラス属性を使って Model
から継承したクラスを定義することでデータモデルを定義します。次に例を示します。
...
ここで、username
、userid
、email
は Account
のプロパティです。
他にもいくつかのプロパティ型があります。日付や時刻の表現に役立つものや、便利な自動更新機能を持つものがあります。
アプリケーションでは、プロパティ オプションを指定してプロパティの動作をカスタマイズできます。これを利用して、検証の簡素化、デフォルトの設定、クエリ インデックスの生成の変更を行うことができます。
モデルには、より複雑なプロパティを設定できます。反復プロパティはリストに似ています。構造化プロパティはオブジェクトに似ています。読み取り専用の計算済みプロパティは関数で定義します。そのため、1 つ以上の他のプロパティに基づくプロパティを簡単に定義できます。Expando モデルではプロパティを動的に定義できます。