Datastore 中的数据对象被称为实体。实体具有一个或多个命名属性,且每个属性可具有一个或多个值。相同种类的实体无需具有相同的属性,且实体的给定属性的值无需都是同一数据类型。(必要时,应用可在其自身的数据模型中设定和实施此类限制)。
Datastore 支持多种属性值数据类型,其中包括:
- 整数
- 浮点数
- 字符串
- 日期
- 二进制数据
如需查看类型的完整列表,请参阅属性和值类型。
Datastore 中的每个实体都有一个唯一标识它的键。键由以下部分组成:
- 实体的命名空间,可实现多租户
- 实体所属的种类,用于对实体进行分类以执行 Datastore 查询
- 具体实体的标识符,可以是下面任意一种
- 键名字符串
- 整数数字 ID
- (可选)祖先路径,用于在 Datastore 层次结构中确定实体的位置
应用可以使用具体实体的键从 Datastore 中提取该实体,也可以根据实体的键或属性值发出查询以检索一个或多个实体。
Go App Engine SDK 包含一个软件包,用于将 Datastore 实体表示为 Go 结构体,此外还用于在 Datastore 中存储和检索这些实体。
Datastore 本身并不对实体结构施加任何限制,例如限制给定属性采用特定类型的值;该任务由应用执行。
种类和标识符
每个 Datastore 实体均属于特定“种类”,如此可将实体进行分类以便于查询;例如,人力资源应用可以通过种类为 Employee
的实体来表示公司的每位员工。在 Go Datastore API 中,您可以在创建 datastore.Key 时指定一个实体的种类。以两个下划线 (__
) 字符开头的所有种类名称均属于保留名称,不得使用。
以下示例创建种类为 Employee
的实体,填充其属性值,并将其保存到 Datastore:
Employee
类型声明了该数据模型的四个属性:FirstName
、LastName
、HireDate
、AttendedHRTraining
。
除了种类,在创建实体时还会为每个实体分配标识符。标识符是实体键的一部分,因此与实体永久关联且不可更改。标识符可通过下述两种方式分配:
- 应用可为实体指定自己的键名字符串。
- 您可让 Datastore 自动为实体分配一个整数数字 ID。
要为实体分配键名,请将一个非空 stringID
参数提供给 datastore.NewKey
:
如需让 Datastore 自动分配数字 ID,请使用空的 stringID
参数:
分配标识符
Datastore 可配置为使用两种不同的自动 ID 政策生成自动 ID:
default
政策会生成大致均匀分布的未使用 ID 的随机序列。每个 ID 最多可包含 16 位十进制数字。legacy
政策会创建一系列不连续的较小整数 ID。
如果希望向用户显示实体 ID 和/或按照顺序显示实体 ID,最好是使用手动分配。
Datastore 生成大致均匀分布的未使用 ID 的随机序列。每个 ID 最多可包含 16 位十进制数字。
祖先路径
Cloud Datastore 中的实体形成一个与文件系统目录结构类似的层级结构空间。创建实体时,您可选择指定另一实体作为其父实体;新实体是父实体的子实体(请注意,与文件系统不同,无需实际存在父实体)。没有父实体的实体是根实体。实体与其父实体之间的关联是永久的,实体创建后就无法更改。Cloud Datastore 绝不向父实体相同的两个实体分配同一数字 ID,也不分配给两个根实体(即没有父实体的实体)。
实体的父实体、父实体的父实体和以此类推得出的实体都是该实体的祖先实体;而实体的子实体和子实体的子实体等都是它的后代实体。根实体及其所有后代实体都属于同一个实体组。实体序列从根实体开始,接着从父实体到子实体,再指向给定的实体,这就构成了实体的祖先路径。识别实体的完整键由一系列种类/标识符对构成,它们指定实体的祖先路径并以实体自身的种类/标识符对终止。
[Person:GreatGrandpa, Person:Grandpa, Person:Dad, Person:Me]
对于根实体,祖先路径为空,且键仅由实体自身的种类和标识符组成:
[Person:GreatGrandpa]
此概念如下图所示:
如需指定实体的父实体,请将 parent
参数用于 datastore.NewKey
。该参数的值应是父实体的键。以下示例将创建种类为 Address
的实体,并将 Employee
实体指定为其父实体:
事务和实体组
每次尝试创建、更新或删除实体时,这些操作都将在事务上下文中进行。单个事务可以包括任意数量的此类操作。为保持数据的一致性,事务确保其包含的所有操作作为一个单元应用于 Datastore,只要有任何操作失败,则所有操作都不会应用。此外,在同一个事务中执行的所有强一致读取(祖先查询或 get 方法)都遵从一致的数据快照。
如上所述,实体组是一组通过祖先实体连接到共同根元素的实体。将数据整理成实体组可以限制可执行的事务:
- 一个事务所访问的所有数据都必须包含在最多 25 个实体组中。
- 如果想在事务内使用查询,必须将数据整理成实体组,如此用户才可以指定与正确数据匹配的祖先过滤器。
- 单个实体组的写入吞吐量限制为每秒约一个事务。存在此限制是因为 Datastore 会在大范围的地理区域内,对每个实体组执行无主同步复制,以提供高可靠性和容错性。
在许多应用中,可在广泛查看互不相关数据时使用最终一致性(即跨多个实体组进行非祖先查询,有时可能会返回稍过时的数据),然后在查看或修改一组高度相关的数据时,使用强一致性(祖先查询,或使用 get
方法查询单个实体)。在此类应用中,通常适合为每组高度相关的数据使用独立的实体组。如需了解详情,请参阅设计结构以确保高度一致性。
属性和值类型
与实体关联的数据值由一个或多个属性构成。每个属性都有一个名称和一个或多个值。一个属性可具有多个类型的值,且两个实体的同一属性可具有不同类型的值。属性可以编入索引,也可以不编入索引(对属性 P 排序或过滤的查询会忽略未将 P 编入索引的实体)。一个实体最多可以有 20000 个编入索引的属性。
值类型 | Go 类型 | 排列顺序 | 备注 |
---|---|---|---|
整数 | int int8 int16 int32 int64 |
数字 | 64 位整数,有符号 |
浮点数 | float32 float64 |
数字 | 64 位双精度, IEEE 754 |
布尔值 | bool |
false <true |
|
字符串(短) | string |
Unicode |
最多 1500 字节。长度超过 1500 字节的值会导致运行时出错。 |
字符串(长) | string (带 noindex ) |
无 | 最多 1 兆字节 未编入索引 |
字节切片(短) | datastore.ByteString |
字节顺序 | 最多 1500 字节。长度超过 1500 字节的值会导致运行时出错。 |
字节片(长) | []byte |
无 | 最多 1 兆字节 未编入索引 |
日期和时间 | time.Time |
时间顺序 | |
地理位置点 | appengine.GeoPoint |
先按纬度排序, 再按经度排序 |
|
Datastore 键 | *datastore.Key |
按路径元素 (种类、标识符、 种类、标识符...)排序 |
|
Blobstore 键 | appengine.BlobKey |
字节顺序 |
您还可以使用 struct
或 slice
来聚合属性。如需了解详情,请参阅 Datastore 参考文档。
如果查询涉及的属性具有混合类型的值,Datastore 会根据内部表示法确定排序方式:
- Null 值
- 定点数
- 整数
- 日期和时间
- 布尔值
- 字节序列
- 字节切片(短)
- Unicode 字符串
- Blobstore 键
- 浮点数
- 地理位置点
- Datastore 键
由于长字节片和长字符串未编入索引,因此它们没有定义排序方式。
处理实体
应用可以使用 Datastore API 创建、检索、更新和删除实体。如果应用知道完整的实体键(或可从其父键、种类和标识符中提取),则可使用此键直接操作实体。应用还可以通过 Datastore 查询获取实体的键;如需了解详情,请参阅 Datastore 查询页面。
创建实体
在 Go 中,您可以通过以下方式创建一个新实体:构造 Go 结构体的实例,填充其字段,并调用 datastore.Put
将其保存到 Datastore。只有所导出的字段(以大写字母开头)会保存到 Datastore。您可以通过将非空 stringID
参数传递给 datastore.NewKey
来指定实体的键名:
未提供键名或使用 datastore.NewIncompleteKey
时,Datastore 将自动为实体的键生成数字 ID:
检索实体
如需检索由给定键标识的实体,请将 *datastore.Key
作为参数传递给 datastore.Get
函数。您可以使用 datastore.NewKey
函数生成 *datastore.Key
。
datastore.Get
将填充相应 Go 结构体的实例。
更新实体
如需更新现有实体,请修改结构体的属性,然后调用 datastore.Put
。数据将覆盖现有实体。每次调用 datastore.Put
时,整个对象都会发送到 Datastore。
删除实体
如果您知道实体的键,可以使用 datastore.Delete
函数删除实体:
批量操作
datastore.Put
、datastore.Get
、datastore.Delete
具有批量变体,分别称为 datastore.PutMulti
、datastore.GetMulti
、datastore.DeleteMulti
。它们允许在单次 Datastore 调用中对多个实体执行操作:
批量操作不会改变费用。无论批量操作中的每个键是否存在,您都要为各个键付费。操作所涉及的实体大小不会影响费用。