部分字段查询和更新
部分字段查询和更新
Pb对象是嵌套树结构,完整的Pb message可能会较大,tcaplus可支持对部分字段或嵌套字段的查询和更新,如”timekey”, “pay.order.desc”, “str_map[‘key’].desc”。
部分字段接口的更新范围也会影响新老proto共存时的数据结果。叶子字段更新、父message替换和完整message写入的兼容性差异见《PB 表数据读写与版本兼容性》。
示例表:
message tb_online3 {
option(tcaplusservice.tcaplus_primary_key) = "openid";
message order_info {
int32 oid = 1;
string desc = 2;
}
message pay_info {
double total_money = 1;
uint64 pay_times = 2;
order_info order = 3;
int32 pid = 4;
string desc = 5;
}
int32 openid = 1;
uint32 tconndid = 2;
string timekey = 3;
repeated int64 lockid = 4;
pay_info pay = 5;
repeated pay_info pay_array = 6;
repeated string desc_array = 7;
map<int32, all_type_t> int_map = 9;
map<string, all_type_t> str_map = 10;
map<string, string> str_str = 11;
}
部分字段查询
Pb表支持部分字段查询,见FieldGet接口,大致参数如下:
- 入参&出参:pb message,message中的key,作为输入;查询成功之后,返回的数据会回填到这个message中作为输出。
- 入参:field_paths,指定的要更新的字段集合,如{“timekey”, “pay.order.desc”, “str_map[‘key’].desc”}。
- 入参:condition,条件过滤,仅当条件满足时才返回,否则会返回条件不匹配的错误码
COMMON_ERR_CONDITION_NOT_MATCHED。
支持以下类型的字段:
- 一级字段,如”timekey”、“pay”、“desc_array”。
- 嵌套字段,如”pay.order.desc”。
- Map的元素的嵌套字段,如”int_map[1001]”、“str_str[‘key’],对于”str_map[‘key’].desc”,若map的key不存在则报错
COMMON_ERR_ELEMENT_NOT_EXIST。 - 数组的嵌套字段,如”pay_array[0]”、“pay_array[0].order.desc”,若数组下标不存在则报错。
- 数组范围,如”pay_array[0-100]”、“pay_array[0- -1]“,其中-1表示直到末尾。
- 一趟请求,可支持对多个字段进行查询,如{“timekey”, “pay.order.desc”, “str_map[‘key’].desc”}。
- 但是多字段不能有路径重叠,如{“pay”, “pay.order.desc”},可能得不到预期结果。
字段路径的总结,使用点号(.)表示嵌套字段,使用方括号([])表示数组索引和map key,不支持路径中使用多个方括号([]),如”map[‘key’].a.sub_map[‘sub_key’]”。
List表的ListGet也可以只查询元素的部分字段(C++ SDK通过ListGetRequest::m_setPaths指定),但只支持点号分隔的一级字段和嵌套字段,如”gamesvrid”、“pay.pay_times”,不支持map key和数组下标,见《[List表]查询列表中指定位置的元素》。
部分字段更新
Pb表支持部分字段更新,见C++ SDK的FieldSet接口,Go SDK的FieldUpdate接口。
FieldSet或FieldUpdate的行为如下:
- 入参&出参:pb message,message中的key和包含的增量数据,作为输入;更新成功之后,返回的数据会回填到这个message中。
- 入参:field_paths,指定的要更新的字段集合,如{“timekey”, “pay.order.desc”, “str_map[‘key’].desc”}。
- 入参:operation,额外捎带的文本描述的操作,如”pay.pay_times += 1”。
- 入参:condition,条件过滤,仅当条件满足时才更新,否则会返回条件不匹配的错误码
COMMON_ERR_CONDITION_NOT_MATCHED。
部分字段更新,支持以下这些类型的字段:
- 一级字段的更新,如”timekey”、“pay”、“desc_array”。
- 嵌套字段,如”pay.order.desc”。
- Map的元素的嵌套字段,如”int_map[1001]”、“str_map[‘key’].desc”、“str_str[‘key’],若map的key不存在则创建之。
- Map元素的插入,如”PUSH int_map[1001]“,若map的key已存在则报错。
- Map元素的删除,如”POP int_map[1001]“,若map的key不存在,也会返回成功。
- 一趟请求,可支持对多个字段进行更新,会同时生效,如{“timekey”, “pay.order.desc”, “str_map[‘key’].desc”}。
- 但是多字段更新不能有路径重叠,如{“pay”, “pay.order.desc”},不会报错,但因为更新顺序问题可能得不到预期结果。
字段路径决定覆盖范围。例如,更新pay.order.desc只修改叶子字段;更新pay则替换整个父message。新老proto共存时,父message中未被旧proto识别的字段能否保留,取决于提交的pay是否携带对应UnknownField。
因为对Map元素的更新,可以支持一种类Schema-free的用法,见《Schema-free》。
不支持像map元素一样,对数组元素的更新(即repeated字段):
- 不支持数组元素的嵌套字段,如”pay_array[0]”、“pay_array[0].desc”,只支持数组字段的整体更新(即”pay_array”)。
- 若要更新数组,只能通过operation语句对数组元素进行PUSH、SET、POP操作,文本语法见《条件过滤和更新语法说明》,能力与限制见《条件过滤和更新功能》。
字段路径的总结,使用点号(.)表示嵌套字段,使用方括号([])表示map key(不支持数组索引),不支持路径中使用多个方括号([]),如”map[‘key’].a.sub_map[‘sub_key’]”。
记录不存在时创建
默认,当修改的记录不存在时,会报错TXHDB_ERR_RECORD_NOT_EXIST。 若希望记录不存在时,自动创建,可通过接口SetMessageOption设置。
C++SDK相关接口:
/**
* i).MESSAGE_OPTION_ENABLE_SET_NOT_EXIST = 9, API中设置允许FieldSet操作不存在的记录时创建之,取值0不允许,取值1允许
*/
int SetMessageOption(const ::google::protobuf::Message &msg, int32_t item, const std::string &option);
GoSDK相关接口:
const (
TcaplusFlagInsertRecordIfNotExist int32 = 16 //PB的FieldUpdate使用,数据不存在则插入
)
func (req *pbFieldUpdateRequest) SetFlags(flag int32) int
ResultFlag
更新返回之后,默认总是把请求的key和增量数据回填到原message(入参&出参)。 而有些场景下,需要返回其他数据,如更新前的旧数据,接口SetMessageOption支持设置返回数据。
C++SDK相关接口:
/**
* j).MESSAGE_OPTION_RESULT_FLAG_FOR_SUCCESS = 10, 用户显式设置请求执行成功时的响应标志,会覆盖API的默认配置
* option取值有 "0":表示只需返回操作执行成功与否
* "1":表示返回与请求字段一致
* "2":表示须返回变更记录的所有字段最新数据
* "3":表示须返回变更记录的所有字段旧数据
* 其中,对于FieldSet操作,不设置该选项,总是返回和请求一致的数据
* k).MESSAGE_OPTION_RESULT_FLAG_FOR_FAIL = 11, 用户显式设置请求执行失败时的响应标志,会覆盖API的默认配置
* option取值有 "0":表示只需返回操作执行成功与否
* "1":表示返回与请求字段一致
* "2":表示须返回变更记录的所有字段最新数据
* "3":表示须返回变更记录的所有字段旧数据
* 其中,对于FieldSet操作,不设置该选项,总是返回和请求一致的数据
*/
int SetMessageOption(const ::google::protobuf::Message &msg, int32_t item, const std::string &option);
GoSDK相关接口:
const (
TcaplusResultFlagNoValue byte = 0
TcaplusResultFlagSameWithRequest byte = 1
TcaplusResultFlagAllNewValue byte = 2
TcaplusResultFlagAllOldValue byte = 3
)
func (req *pbFieldUpdateRequest) SetResultFlagForSuccess(result_flag byte) int
func (req *pbFieldUpdateRequest) SetResultFlagForFail(result_flag byte) int
当option取值2、3时,返回的是记录的所有字段数据(非部分修改字段),若完整记录数据较大时,高频操作会占用较大的网路带宽。
List表部分字段更新(ListReplace)
PB List表的ListReplace(C++ SDK的ListReplace接口,Go SDK的DoListReplace接口)也支持部分字段更新,对标Generic表的FieldSet(Go SDK为FieldUpdate)。
语义说明:接口名称虽然是ListReplace,实际是ListUpdate的语义:
- 必须指定元素的index,且该元素必须已存在。key对应的List不存在时返回
TXHDB_ERR_RECORD_NOT_EXIST,index不存在时返回SVR_ERR_FAIL_INVALID_INDEX。ListReplace不会插入新元素,也不支持记录不存在时创建。 - 默认(不指定字段路径)是整个message覆盖式更新:用请求中的message替换该元素的全部value字段,message中未设置的字段会被清空。
- 指定字段路径时(C++ SDK的
ListReplaceRequest::m_setPaths,Go SDK的option.PBOpt.FieldNames),只更新这些字段,其余字段保持不变。字段路径的写法与限制同上文《部分字段更新》中的FieldSet/FieldUpdate,如嵌套字段、map元素的更新与PUSH/POP,路径中不能包含key字段。 - condition在更新前对元素的当前数据进行判断,不满足时返回
COMMON_ERR_CONDITION_NOT_MATCHED,元素保持不变。 - operation是更新之后的后置更新动作:TcaplusDB先完成字段更新(或整个message覆盖),再在更新后的元素上执行operation,二者在同一次请求内完成。operation支持标量字段的
+=、-=和数组的PUSH、SET、POP,语法见《条件过滤和更新语法说明》§6,能力与限制见《条件过滤和更新功能》§5。 - SortList表更新了排序字段时,元素会按更新后的值重新排序。
示例代码见《[PB List表][C++ SDK]更新列表中指定位置的元素》4.2:只更新gamesvrid和pay.pay_times,并在更新后向lockid尾部追加一个元素。
返回数据:与FieldSet默认返回和请求一致的数据不同,ListReplace按以下规则返回(C++ SDK通过SetMessageOption设置MESSAGE_OPTION_RESULT_FLAG_FOR_SUCCESS、MESSAGE_OPTION_RESULT_FLAG_FOR_FAIL,Go SDK通过option.PBOpt的ResultFlagForSuccess、ResultFlagForFail设置):
- C++ SDK未设置时,成功返回更新后的完整元素;只关心执行结果时,建议设为”0”不返回数据。Go SDK需要显式设置
ResultFlagForSuccess才返回数据。 - 成功时设为”1”(返回与请求一致)不返回数据;设为”2”返回更新后的完整元素,设为”3”返回更新前的完整元素。
- 失败时设为”3”:条件不满足、版本冲突、字段更新失败等已读到元素的场景,返回更新前的完整元素;key或index不存在时不返回数据。
返回的都是元素的全部字段,而不是请求中的部分字段。
批量更新不支持部分字段更新:ListUpdateBatch(C++ SDK的ListBatchUpdate接口,Go SDK的DoListReplaceBatch接口)暂不支持部分字段更新,每个元素总是整个message覆盖;需要部分更新时,请逐条调用ListReplace。
版本要求:部分字段更新需C++ PB SDK 3.55.0 SP06(3.55.0.209070)及以上,或Go SDK v0.6.36及以上;服务端须为Tcapsvr 3.73.0 2026-10-10以后的版本,旧版后端需要先升级再使用该功能。
各SDK的接口说明见《[PB List表][C++ SDK]更新列表中指定位置的元素》、《[PB List表][Go SDK]更新列表中指定位置的元素》。