Datastore 模式的 Firestore (Datastore) 支持多种属性值数据类型。其中包括:
- 整数
- 浮点数
- 字符串
- 日期
- 二进制数据
如需查看类型的完整列表,请参阅 属性和值类型。
属性和值类型
与实体关联的数据值由一个或多个属性构成。 每个属性都有一个名称和一个或多个值。属性可具有多个类型的值,且两个实体的同一属性可具有不同类型的值。属性可以编入索引,也可以不编入索引(对属性 P 排序或过滤的查询会忽略未将 P 编入索引的实体)。一个实体最多可以有 20,000 个编入索引的属性。
如果查询涉及的属性具有混合类型的值,Datastore 会根据内部表示法确定排序方式:
- Null 值
- 定点数
- 整数
- 日期和时间
- 布尔值
- 字节序列
- Unicode 字符串
- Blobstore 键
- 浮点数
- Datastore 键
因为 长文本字符串和长字节字符串 未编入索引,因此它们没有定义排序顺序。
属性类型
NDB 支持以下属性类型:
属性类型 | 说明 |
---|---|
IntegerProperty |
64 位有符号整数 |
FloatProperty |
双精度浮点数 |
BooleanProperty |
布尔值 |
StringProperty |
Unicode 字符串;最多 1500 个字节,编入索引 |
TextProperty |
Unicode 字符串;长度无限,不编入索引 |
BlobProperty |
未解析的字节字符串: 如果设置 indexed=True ,最多 1500 个字节,编入索引;如果 indexed 为 False (默认),长度无限,不编入索引。可选的关键字参数: compressed 。 |
DateTimeProperty |
日期和时间(请参阅日期和时间属性) |
DateProperty |
日期(请参阅日期和时间属性) |
TimeProperty |
时间(请参阅日期和时间属性) |
GeoPtProperty |
地理位置。这是一个 ndb.GeoPt 对象。该对象具有 lat 和 lon 属性(两者均为浮点数)。您可以使用两个浮点数构建一个这样的对象,例如 ndb.GeoPt(52.37, 4.88) ;或使用字符串构建,例如 ndb.GeoPt("52.37, 4.88") 。(这实际与 db.GeoPt 是同一个类) |
KeyProperty |
Datastore 键 可选的关键字参数:kind=kind,要求分配给此属性的键始终具有所指示的类。可能是一个字符串或一个 Model 子类。 |
BlobKeyProperty |
Blobstore 键 相当于旧版 db API 中的 BlobReferenceProperty ,但属性值是 BlobKey 而不是 BlobInfo ;您可以使用 BlobInfo(blobkey) 从 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 时间,通常最佳做法是只有当数据太大必须压缩时才会使用压缩属性。请记住,基于 gzip 的压缩通常对图像和其他媒体数据无效,因为这些格式已经使用特定媒体压缩算法(例如,用于图像的 JPEG)压缩过。
属性选项
大多数属性类型都支持一些标准参数。第一个参数是用于指定属性的 Datastore 名称的可选位置参数。从应用的角度考虑,您可以使用此参数给予属性一个不同的 Datastore 名称。在 Datastore 中,此参数常用于缩小占用空间,既可让 Datastore 使用缩写的属性名称,又可让您的代码使用更长、更有意义的属性名称。例如,
这对预计每个实体有多个值的重复属性来说特别有用。
此外,大多数属性类型都支持以下关键字参数:
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
indexed |
bool |
通常为 True |
在 Datastore 的索引中包括属性;如果为 False ,则无法查询值,但写入速度会更快。并非所有属性类型都支持索引;对于这些属性将 indexed 设置为 True 会失败。未编入索引的属性需要的写入操作次数比编入索引的属性少。 |
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 |
字符串 | None |
可选的 HTML 标签,用于 jinja2 等 Web 表单框架。 |
重复属性
任何具有 repeated=True
的属性都是重复属性。该属性给出基础类型值(而不是单个值)的列表。例如,使用 IntegerProperty(repeated=True)
定义的属性值是整数列表。
Datastore 可以查看此类属性的多个值。系统会为每个值创建单独的索引记录。这会影响查询语义;请参阅查询重复属性,查看示例。
此示例使用重复属性:
...
这会创建一个 Datastore 实体,其中包含以下内容:
查询 tags
属性时,此实体将满足 'python'
或 'ruby'
查询。
在更新重复属性时,您可以为其分配新列表或更改现有列表。当您分配新列表时,列表项的类型会立即得到验证。无效项类型(例如,为上述 art.tags
分配 [1, 2]
)会引发异常。当您更改列表时,更改的内容不会立即得到验证。相反,当您将实体写入 Datastore 时,值会得到验证。
Datastore 在重复属性中保留了列表项的顺序,因此您可以为其排序方式指定某种含义。
日期和时间属性
有三种属性类型可用于存储与日期和时间相关的值:
DateProperty
TimeProperty
DateTimeProperty
这些属性类型获取的值属于标准 Python datetime
模块的对应类(date
、time
、datetime
)。这三种属性类型中最常见的是用于表示日历日期和一天中时间的 DateTimeProperty
,其他两种属性类型偶尔用于仅需要日期(出生日期)或时间(如会议时间)的特殊目的。因技术原因,DateProperty
和 TimeProperty
都是 DateTimeProperty
的子类,但您不应依赖此继承关系(请注意它不同于 datetime
模块本身定义的基础类之间的继承关系)。
这些属性每个都有两个额外的布尔值关键字选项:
选项 | 说明 |
---|---|
auto_now_add |
创建实体时,将属性设置为当前日期/时间。您可以手动替换此属性。更新实体时,该属性不会更改。如果需要在更新时更改属性,请使用 auto_now 。 |
auto_now |
创建和任何时候更新实体时,将属性设置为当前日期/时间。 |
这些选项不能与 repeated=True
搭配使用。这两个选项默认为 False
;如果这两者都设置为 True
,则 auto_now
具有优先权。可以替换 auto_now_add=True
的属性值,但不能替换 auto_now=True
的属性值。写入实体后,才会生成自动值;也就是说,这些选项不提供动态默认值。(这些细节与旧的 db API 不同。)
结构化属性
您可以构建模型的属性。例如,您可以定义一个含有地址列表的模型类 Contact,每个地址都有其内部结构。
结构化属性(类型为 StructuredProperty
``)可用于执行此操作,例如:
...
...
这会创建一个具有以下属性的 Datastore 实体:
读回此类实体将完全重建原始的 Contact
实体。
虽然 Address
实例是使用模型类所用的语法定义的,但它们并不是完整实体。它们在 Datastore 中没有自己的键,也无法独立于其所属的 Contact
实体而被检索。不过,应用可以查询其各个字段的值;请参阅筛选结构化属性值。
请注意,从 Datastore 的角度来看,address.type
、address.street
和 address.city
被视为并行数组,但 NDB 库隐藏了这一方面并构建 Address
实例的对应列表。
您可以为结构化属性指定常用属性选项(indexed
除外)。在这种情况下,Datastore 名称是第二个位置参数(第一个是用于定义子结构的模型类)。
如果您不需要查询子结构的内部属性,则可以改用本地结构化属性 (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'}>
该实体将被正确读回。由于此类型的属性始终不会编入索引,因此您无法查询地址值。
计算属性
计算属性 (ComputedProperty
) 是只读属性,其值是由应用提供的函数通过其他属性值计算得出的。请注意,计算属性仅支持通用属性支持的类型!计算值将写入 Datastore 中,以便该值可在 Datastore 查看器中查询和显示。但是当从 Datastore 中读回该实体时,存储值会被忽略。确切地说,每当请求该值时,都会调用函数重新计算。例如:
...
这会存储具有以下属性值的实体:
如果我们将名称更改为“Nickie”,并请求 name_lower
的值,它会返回“nickie”:
Google Protocol RPC Message 属性
Google Protocol RPC 库为结构化数据使用 Message
对象,它们可以表示 RPC 请求、响应或其他内容。NDB 提供了一个 API,可让您将 Google Protocol RPC Message
对象存储为实体属性。假设您定义了一个 Message
子类:
...
您可以使用 NDB 的 msgprop
API,在 Datastore 上将 Note
对象存储为实体属性值。
...
...
如果您要查询字段名称,则字段名称必须编入索引。您可以使用 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
且具有某些属性 (property) 类特性 (attribute) 的类来定义数据模型。例如:
...
此处,username
、userid
和 email
都是 Account
的属性。
有多个其他属性类型。其中一些对表示日期和时间非常有用,并且具有方便快捷的自动更新功能。
应用可以指定属性上的选项来调整属性的行为,这些选项可以简化验证、设置默认值或更改查询索引。
模型可以有更复杂的属性。重复属性类似于列表。 结构化属性类似于对象。只读计算属性是通过函数定义的;这可以让您根据一个或多个其他属性轻松定义属性。 Expando 模型可以动态地定义属性。