Skip to content

Commit 78bf126

Browse files
authored
docs(base): align record write schema guidance (#2000)
* docs(base): align record write schema guidance * docs(base): use canonical select field naming * docs(base): simplify select option guidance
1 parent 4eefe32 commit 78bf126

11 files changed

Lines changed: 34 additions & 33 deletions

shortcuts/base/base_execute_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2435,16 +2435,14 @@ func TestBaseRecordExecuteReadCreateDelete(t *testing.T) {
24352435
Body: map[string]interface{}{
24362436
"code": 0,
24372437
"data": map[string]interface{}{
2438-
"fields": []interface{}{"Name"},
24392438
"record_id_list": []interface{}{"rec_1", "rec_2"},
2440-
"data": []interface{}{[]interface{}{"Alice"}, []interface{}{"Bob"}},
24412439
},
24422440
},
24432441
})
2444-
if err := runShortcut(t, BaseRecordBatchCreate, []string{"+record-batch-create", "--base-token", "app_x", "--table-id", "tbl_x", "--json", `{"fields":["Name"],"rows":[["Alice"],["Bob"]]}`}, factory, stdout); err != nil {
2442+
if err := runShortcut(t, BaseRecordBatchCreate, []string{"+record-batch-create", "--base-token", "app_x", "--table-id", "tbl_x", "--json", `{"create_records":[{"Name":"Alice"},{"Name":"Bob"}]}`}, factory, stdout); err != nil {
24452443
t.Fatalf("err=%v", err)
24462444
}
2447-
if got := stdout.String(); !strings.Contains(got, `"record_id_list"`) || !strings.Contains(got, `"rec_1"`) || !strings.Contains(got, `"Alice"`) {
2445+
if got := stdout.String(); !strings.Contains(got, `"record_id_list"`) || !strings.Contains(got, `"rec_1"`) {
24482446
t.Fatalf("stdout=%s", got)
24492447
}
24502448
})

shortcuts/base/base_shortcuts_test.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,8 @@ func TestBaseJSONExamplesLiveInFlagDescriptions(t *testing.T) {
801801
name: "record batch create json",
802802
shortcut: BaseRecordBatchCreate,
803803
wantHelp: []string{
804-
`batch create JSON object, e.g. {"fields":["Name","Status"],"rows":[["Task A","Todo"],["Task B",null]]}; rows follow fields order`,
804+
"create_records contains one field map per record",
805+
`{"create_records":[{"Name":"Task A","Status":"Todo"},{"Name":"Task B","Score":20}]}`,
805806
},
806807
},
807808
{
@@ -850,8 +851,8 @@ func TestBaseRecordWriteHelpGuidesAgents(t *testing.T) {
850851
`{"Parent Link":[{"id":"rec_xxx"}]}`,
851852
"do not look for parent_record_id or a separate child-record API",
852853
"CellValue happy path: text/phone/url",
853-
"select -> \"Todo\"",
854-
"multi-select -> [\"Tag A\",\"Tag B\"]",
854+
"select (multiple=false) -> \"Todo\"",
855+
"select (multiple=true) -> [\"Tag A\",\"Tag B\"]",
855856
"datetime -> \"2026-03-24 10:00:00\"",
856857
"checkbox -> true/false",
857858
`ID-based CellValue: user/group/link fields use arrays like [{"id":"ou_xxx"}]`,
@@ -865,11 +866,11 @@ func TestBaseRecordWriteHelpGuidesAgents(t *testing.T) {
865866
name: "record batch create",
866867
shortcut: BaseRecordBatchCreate,
867868
wantTips: []string{
868-
"Happy path fields: fields is the column order",
869-
"rows is an array of row arrays",
870-
"may use null for empty cells",
869+
"Happy path field: create_records",
870+
"create_records is an array of independent record field maps",
871+
`{"create_records":[{"Name":"Task A","Status":"Todo"},{"Name":"Task B","Score":20}]}`,
871872
"use +field-list to confirm real writable fields",
872-
"Batch create supports max 200 rows per call",
873+
"Batch create supports max 200 records per call",
873874
"do not immediately +record-list the same table",
874875
"CellValue happy path: text/phone/url",
875876
`ID-based CellValue: user/group/link fields use arrays like [{"id":"ou_xxx"}]`,

shortcuts/base/field_search_options.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ var BaseFieldSearchOptions = common.Shortcut{
2727
},
2828
Tips: []string{
2929
`Example: lark-cli base +field-search-options --base-token <base_token> --table-id <table_id> --field-id "Status" --keyword "Do"`,
30-
"Use only for fields with options, such as select or multi-select fields.",
30+
"Use only for select fields, whether multiple is false or true.",
3131
},
3232
Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
3333
if err := validateLimitPageSizeAlias(runtime); err != nil {

shortcuts/base/record_batch_create.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ var BaseRecordBatchCreate = common.Shortcut{
1919
Flags: []common.Flag{
2020
baseTokenFlag(true),
2121
tableRefFlag(true),
22-
{Name: "json", Desc: `batch create JSON object, e.g. {"fields":["Name","Status"],"rows":[["Task A","Todo"],["Task B",null]]}; rows follow fields order`, Required: true},
22+
{Name: "json", Desc: `batch create JSON object; create_records contains one field map per record, e.g. {"create_records":[{"Name":"Task A","Status":"Todo"},{"Name":"Task B","Score":20}]}`, Required: true},
2323
},
2424
Tips: append([]string{
25-
"Happy path fields: fields is the column order; rows is an array of row arrays; each row must match fields order and may use null for empty cells.",
25+
"Happy path field: create_records is an array of independent record field maps.",
26+
`Example: {"create_records":[{"Name":"Task A","Status":"Todo"},{"Name":"Task B","Score":20}]}.`,
2627
"Before writing, use +field-list to confirm real writable fields; do not write system fields, formula, lookup, or attachment fields as normal CellValue.",
27-
"Batch create supports max 200 rows per call.",
28+
"Batch create supports max 200 records per call.",
2829
"After batch-creating known helper rows, use the returned record IDs and your submitted rows; do not immediately +record-list the same table unless you need server-normalized formula/lookup values or failure diagnosis.",
2930
"Use the record-batch-create guide for command limits and edge cases.",
3031
}, recordCellValueHappyPathTips...),

shortcuts/base/record_ops.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const maxBatchGetSelectFieldCount = 100
1919
const maxRecordSearchSelectFieldCount = 50
2020

2121
var recordCellValueHappyPathTips = []string{
22-
`CellValue happy path: text/phone/url -> "text"; number/currency/percent/rating -> 12.5; select -> "Todo"; multi-select -> ["Tag A","Tag B"]; datetime -> "2026-03-24 10:00:00"; checkbox -> true/false.`,
22+
`CellValue happy path: text/phone/url -> "text"; number/currency/percent/rating -> 12.5; select (multiple=false) -> "Todo"; select (multiple=true) -> ["Tag A","Tag B"]; datetime -> "2026-03-24 10:00:00"; checkbox -> true/false.`,
2323
`ID-based CellValue: user/group/link fields use arrays like [{"id":"ou_xxx"}], [{"id":"oc_xxx"}], [{"id":"rec_xxx"}]; location uses {"lng":116.397428,"lat":39.90923}; null clears a cell when allowed.`,
2424
"Do not guess user/chat/linked-record IDs or location coordinates; resolve them first with the relevant contact/im/record lookup flow.",
2525
"Use lark-base-cell-value.md for complex CellValue shapes and special field types; do not invent values for fields not covered by the happy path.",

skills/lark-base/SKILL.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ metadata:
112112
- 表名、字段名、视图名、workflow 配置中的名称必须来自真实返回;跨表场景还要读取目标表结构。
113113
- 删除、角色更新、字段更新等高风险操作遵循 CLI 的 confirmation gate;目标不明确时先用 get/list 消歧。
114114
- 批量写入单批最多 200 条;连续写同一表时串行执行,遇到 `1254291` 按短暂等待后重试处理。
115-
- `+record-batch-update` 使用 `update_records`,按 `record_id -> fields` 映射逐条提交字段值。
116-
- select/multiselect 写入未知选项可能触发平台新增选项;不是要新增时,先用 `+field-list``+field-search-options` 确认可选值。
115+
- `select` 字段只支持写入字段中已有的选项;构造 CellValue 前先用 `+field-list``+field-search-options` 确认目标选项存在。
117116

118117
## 表单与视图细节
119118

skills/lark-base/references/lark-base-cell-value.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
- `--json` 必须是 JSON 对象。
1010
- `+record-upsert`:顶层直接传字段映射:`{"字段名或字段ID": CellValue}`
11-
- `+record-batch-create``rows``CellValue[][]`,列顺序由 `fields` 决定
11+
- `+record-batch-create`使用 `create_records`,其每个元素都是 `Map<FieldNameOrID, CellValue>`
1212
- `+record-batch-update`:使用 `update_records`,其每个 value 都是 `Map<FieldNameOrID, CellValue>`
1313
- 一次 payload 里同一字段只用一种 key(字段名或字段 ID),不要重复。
1414
- 写入前先 `+field-list` 获取字段 `type/style/multiple`,再构造值。
@@ -48,7 +48,7 @@ text 字段的 `style.type` 影响单元格检查逻辑:
4848

4949
### 2.3 select(单选/多选)
5050

51-
单选用选项名字符串;多选用选项名数组。选项名建议与字段配置一致;写入未知选项时平台可能自动新增选项,因此不要把自然语言近义词当成已有选项传入
51+
`select` 字段用 `multiple` 区分单选和多选:`multiple=false` 时传选项名字符串,`multiple=true` 时传选项名数组。只支持写入字段中已有的选项;构造 CellValue 前先用 `+field-list``+field-search-options` 确认目标选项存在
5252

5353
```json
5454
{

skills/lark-base/references/lark-base-record-batch-create.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
## 适用场景(重点)
88

99
- 适合导入 CSV / Excel、外部系统一次性写入新数据。
10-
- 先把输入数据映射到合适的字段类型,再组装 `fields + rows`
10+
- 先把每条输入数据映射为独立的字段对象,再组装到 `create_records`
1111

1212
## 推荐命令
1313

1414
```bash
1515
lark-cli base +record-batch-create --base-token <base_token> --table-id <table_id> \
16-
--json '{"fields":["标题","状态"],"rows":[["任务 A","Open"],["任务 B","Done"]]}'
16+
--json '{"create_records":[{"标题":"任务 A","状态":"Open"},{"标题":"任务 B","状态":"Done"}]}'
1717

1818
lark-cli base +record-batch-create --base-token <base_token> --table-id <table_id> --json @batch-create.json
1919
```
@@ -34,23 +34,25 @@ lark-cli base +record-batch-create --base-token <base_token> --table-id <table_i
3434

3535
本节只说明 `+record-batch-create` 的外层 JSON 形状;CellValue 统一看 [lark-base-cell-value.md](lark-base-cell-value.md)
3636

37-
对象形态:`{"fields":[...],"rows":[...]}`
37+
对象形态:
38+
39+
```json
40+
{"create_records":[{"标题":"任务 A","状态":"Open"},{"标题":"任务 B","状态":"Done"}]}
41+
```
3842

3943
| 字段 | 类型 | 必填 | 说明 |
4044
|------|------|------|------|
41-
| `fields` | `string[]` || 字段 ID 或字段名数组 |
42-
| `rows` | `CellValue[][]` || 二维数组,每一行按 `fields` 同序给 cell;单次最多 200 行 |
45+
| `create_records` | `Array<Map<FieldNameOrID, CellValue>>` || 记录字段对象数组;每条记录可以提交不同字段,单次最多 200 条 |
4346

4447
## 返回重点
4548

46-
返回 `fields``field_id_list``record_id_list``data`,其中 `data``fields` 列顺序对齐
49+
返回 `record_id_list` 和可选的 `ignored_fields`
4750

4851
## 坑点
4952

50-
- `fields` 与每行 `rows` 的列顺序必须一一对应。
51-
- 空单元格必须显式用 `null` 填充。
52-
- 单次最多 200 行,超出需分批写入。
53-
- select 写入未知选项时平台可能自动新增选项;如果不是要新增选项,先确认真实选项名。
53+
- 每个 `create_records` 元素都是独立的记录字段对象,只提交该记录需要写入的字段。
54+
- 单次最多 200 条,超出需分批写入。
55+
- `select` 字段只支持写入字段中已有的选项;构造 CellValue 前先用 `+field-list``+field-search-options` 确认目标选项存在。
5456

5557
## 参考
5658

skills/lark-base/references/lark-base-record-upsert.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ lark-cli base +record-upsert --base-token <base_token> --table-id <table_id> --r
5555
## 坑点
5656

5757
-`--record-id` 就一定更新;不传就一定创建,不会自动查重或按业务键 upsert。
58-
- select 写入未知选项时平台可能自动新增选项;如果不是要新增选项,先用 `+field-list` / `+field-search-options` 确认真实选项名
58+
- `select` 字段只支持写入字段中已有的选项;构造 CellValue 前先用 `+field-list` `+field-search-options` 确认目标选项存在
5959
- 这是写入操作,执行前必须确认目标表和字段。
6060

6161
## 参考

tests/cli_e2e/base/base_record_batch_update_workflow_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func TestBaseRecordBatchUpdatePerRecordWorkflow(t *testing.T) {
3636
"base", "+record-batch-create",
3737
"--base-token", baseToken,
3838
"--table-id", tableID,
39-
"--json", `{"fields":["Name","Status","Score"],"rows":[["alpha","Open",10],["beta","Open",15]]}`,
39+
"--json", `{"create_records":[{"Name":"alpha","Status":"Open","Score":10},{"Name":"beta","Status":"Open","Score":15}]}`,
4040
},
4141
DefaultAs: "bot",
4242
})

0 commit comments

Comments
 (0)