DynamoDB Toolbox 中的 Record 类型详解
什么是 Record 类型
在 DynamoDB Toolbox 中,Record 是一种特殊的映射(Map)属性类型。与常规的 Map 类型不同,Record 具有以下特点:
- 键(key)可以是非显式定义的,数量理论上无限
- 所有值(value)必须是同一类型
- 键必须是字符串类型
这种设计非常适合存储具有动态键但值类型一致的数据结构,例如:
- 配置项集合
- 标签系统
- 多语言文本
- 状态记录
Record 的基本用法
创建 Record 类型非常简单:
import { record } from 'dynamodb-toolbox/schema/record'
// 创建一个键为字符串,值为数字的Record
const scoreRecord = record(string(), number())
// 更复杂的例子:Pokemon弱点记录
const pokeTypeSchema = string().enum('fire', 'water', 'grass', 'electric')
const weaknessesSchema = record(pokeTypeSchema, number())
Record 的特殊约束
Record 类型有一些特殊限制需要注意:
-
值类型限制:
- 不能设置为可选(optional)
- 不能隐藏(hidden)
- 不能作为键(key)
- 不能有默认值(default)
- 不能有链接(links)
-
键类型限制:
- 必须是字符串类型
- 必须符合 DynamoDB 的命名规则
以下代码会引发类型和运行时错误:
// 错误示例 - 值不能是optional
const invalidRecord = record(string(), string().optional())
Record 的高级特性
1. 必填性控制
通过 .required()
方法可以控制 Record 的必填行为:
// 默认情况下是'atLeastOnce',表示初始创建时必须存在
const defaultRequired = record(string(), number())
// 设置为'always'表示每次更新都必须存在
const alwaysRequired = record(string(), number()).required('always')
// 设置为'never'或使用.optional()表示可选
const optionalRecord = record(string(), number()).optional()
2. 隐藏属性
使用 .hidden()
可以在格式化输出时隐藏 Record:
const hiddenRecord = record(string(), number()).hidden()
3. 键属性标记
标记为键属性时,Record 会自动设置为'always'必填:
const keyRecord = record(string(), string()).key()
4. 存储别名
使用 .savedAs()
可以指定存储时的别名:
const aliasedRecord = record(string(), number()).savedAs('r')
5. 部分 Record
.partial()
方法可以将 Record 转换为部分类型:
const partialRecord = record(string(), number()).partial()
// 类型变为 Partial<Record<string, number>>
默认值与链接
Record 支持多种默认值设置方式:
基本默认值
// 设置创建时的默认值
const withDefault = record(string(), number())
.default({ key1: 100, key2: 200 })
动态默认值
const dynamicDefault = record(string(), string())
.default(() => ({
createdAt: new Date().toISOString()
}))
键默认值
const keyDefault = record(string(), string())
.key()
.keyDefault({ id: '123' })
链接其他属性
const userSchema = item({
fullName: string()
}).and(prev => ({
nameParts: record(string(), string()).link<typeof prev>(
({ fullName }) => {
const [first, last] = fullName.split(' ')
return { firstName: first, lastName: last }
}
)
}))
自定义验证
Record 支持自定义验证逻辑:
// 验证Record不为空
const nonEmptyRecord = record(string(), string())
.validate(input => Object.keys(input).length > 0)
// 针对不同操作设置不同验证
const operationSpecific = record(string(), number())
.putValidate(input => Object.keys(input).length <= 10)
.updateValidate(input => Object.keys(input).length <= 5)
实际应用场景
Record 类型非常适合以下场景:
-
多语言内容存储:
const translations = record(string().enum('en', 'zh', 'ja'), string())
-
用户偏好设置:
const userPreferences = record(string(), any())
-
系统指标记录:
const systemMetrics = record(string(), number())
-
标签系统:
const tags = record(string(), boolean())
最佳实践建议
- 键类型约束:尽量使用枚举或有限集合约束键的类型
- 值类型选择:选择最适合业务场景的值类型
- 验证策略:根据业务需求添加适当的验证逻辑
- 默认值设计:考虑使用动态默认值以适应不同场景
- 性能考虑:大型 Record 可能影响查询性能,需合理设计
通过合理使用 Record 类型,可以大大简化 DynamoDB 中复杂数据结构的建模和管理工作。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考