批量操作函数
json 包提供的批量操作函数,支持一次性处理多个 JSON 操作(get/set/delete/validate),适合批量数据处理场景。
ProcessBatch
签名:func ProcessBatch(operations []BatchOperation, cfg ...Config) ([]BatchResult, error)
批量处理多个 JSON 操作(包级函数,无需创建 Processor)。返回结果顺序与输入操作顺序一一对应,通过 ID 字段关联。
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
jsonStr := `{"user": {"name": "CyberGo", "age": 25}}`
operations := []json.BatchOperation{
{Type: "get", JSONStr: jsonStr, Path: "user.name", ID: "op1"},
{Type: "set", JSONStr: jsonStr, Path: "user.age", Value: 30, ID: "op2"},
}
results, err := json.ProcessBatch(operations)
if err != nil {
panic(err)
}
for _, r := range results {
if r.Error != nil {
fmt.Printf("操作 %s 失败: %v\n", r.ID, r.Error)
} else {
fmt.Printf("操作 %s 结果: %v\n", r.ID, r.Result)
}
}
}
// 输出:
// 操作 op1 结果: CyberGo
// 操作 op2 结果: {"user":{"age":30,"name":"CyberGo"}}支持的操作类型
Type | 作用 | Result 内容 | 典型错误 |
|---|---|---|---|
get | 读取路径上的值 | 路径处的值(any) | ErrPathNotFound、ErrInvalidJSON |
set | 设置路径的值 | 修改后的完整 JSON 字符串 | ErrPathNotFound(未开 CreatePaths)、ErrInvalidPath |
delete | 删除路径上的节点 | 删除后的完整 JSON 字符串 | ErrPathNotFound、ErrInvalidPath |
validate | 验证 JSON 是否合法 | map[string]any{"valid": bool} | 无效 JSON 时 Result.valid=false 且 Error 非空 |
操作互不链式
每个 BatchOperation 都独立作用于各自的 JSONStr 输入,操作之间不会链式叠加。例如对同一文档先 set 再 delete,得到的是两个独立结果,而不是「先改再删」的叠加态。若需对单个文档做多步变换,请在代码中将上一步的输出喂给下一步,或改用 SetMultiple 等单文档多路径方法。
批量大小限制
操作数量受 Config.MaxBatchSize 约束(默认 2000)。超出时整个批次直接失败,返回 (nil, ErrSizeLimit):
// 自定义上限(适用于超大批量场景)
cfg := json.DefaultConfig()
cfg.MaxBatchSize = 5000
results, err := json.ProcessBatch(ops, cfg)各操作类型示例
get — 批量读取
get 操作的 Result 是路径处的原始值(数字默认为 float64,布尔为 bool,字符串为 string)。
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
data := `{"user":{"name":"CyberGo","age":25},"active":true}`
results, err := json.ProcessBatch([]json.BatchOperation{
{Type: "get", JSONStr: data, Path: "user.name", ID: "name"},
{Type: "get", JSONStr: data, Path: "user.age", ID: "age"},
{Type: "get", JSONStr: data, Path: "active", ID: "active"},
})
if err != nil {
panic(err)
}
for _, r := range results {
if r.Error != nil {
fmt.Printf("%s 失败: %v\n", r.ID, r.Error)
continue
}
fmt.Printf("%s = %v\n", r.ID, r.Result)
}
}
// 输出:
// name = CyberGo
// age = 25
// active = trueset — 批量修改
set 操作的 Result 是修改后的完整 JSON 字符串(注意不是写入的值本身)。默认配置 CreatePaths=true,因此设置新路径会自动创建中间节点。
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
data := `{"user":{"name":"CyberGo","age":25}}`
results, err := json.ProcessBatch([]json.BatchOperation{
{Type: "set", JSONStr: data, Path: "user.age", Value: 30, ID: "update-age"},
{Type: "set", JSONStr: data, Path: "user.role", Value: "admin", ID: "add-role"},
})
if err != nil {
panic(err)
}
for _, r := range results {
if r.Error != nil {
fmt.Printf("%s 失败: %v\n", r.ID, r.Error)
continue
}
fmt.Printf("%s -> %s\n", r.ID, r.Result)
}
}
// 输出:
// update-age -> {"user":{"age":30,"name":"CyberGo"}}
// add-role -> {"user":{"age":25,"name":"CyberGo","role":"admin"}}输出格式说明
set/delete 返回的 JSON 字符串为紧凑格式(无多余空白),且对象键按字典序排列(与 encoding/json 行为一致,保证输出确定)。若需美化输出,请对结果另用 Prettify。
delete — 批量删除
delete 操作的 Result 是删除后的完整 JSON 字符串。
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
data := `{"user":{"name":"CyberGo","age":25,"temp":"x"},"debug":true}`
results, err := json.ProcessBatch([]json.BatchOperation{
{Type: "delete", JSONStr: data, Path: "user.temp", ID: "drop-temp"},
{Type: "delete", JSONStr: data, Path: "debug", ID: "drop-debug"},
})
if err != nil {
panic(err)
}
for _, r := range results {
if r.Error != nil {
fmt.Printf("%s 失败: %v\n", r.ID, r.Error)
continue
}
fmt.Printf("%s -> %s\n", r.ID, r.Result)
}
}
// 输出:
// drop-temp -> {"debug":true,"user":{"age":25,"name":"CyberGo"}}
// drop-debug -> {"user":{"age":25,"name":"CyberGo","temp":"x"}}validate — 批量验证
validate 操作的 Result 始终是 map[string]any{"valid": bool};当 JSON 非法时 valid 为 false 且 Error 携带解析错误。
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
results, err := json.ProcessBatch([]json.BatchOperation{
{Type: "validate", JSONStr: `{"name":"CyberGo"}`, ID: "ok"},
{Type: "validate", JSONStr: `{"name":}`, ID: "broken"},
})
if err != nil {
panic(err)
}
for _, r := range results {
if m, ok := r.Result.(map[string]any); ok {
fmt.Printf("%s: valid=%v\n", r.ID, m["valid"])
}
if r.Error != nil {
fmt.Printf("%s 错误: %v\n", r.ID, r.Error)
}
}
}
// 输出:
// ok: valid=true
// broken: valid=false
// broken 错误: invalid JSON: ...错误处理与容错
单操作失败不中断批次
ProcessBatch 总是处理全部操作:某个操作失败只会写入该条结果的 Error 字段,不会中断后续操作,也无需任何配置开启。因此批量结果可能「部分成功、部分失败」,务必逐条检查 r.Error:
results, err := json.ProcessBatch(operations)
if err != nil {
// err 仅在处理器关闭、配置非法或超过 MaxBatchSize 时出现
panic(err)
}
var failed int
for _, r := range results {
if r.Error != nil {
failed++
log.Printf("操作 %s 失败: %v", r.ID, r.Error)
continue
}
// 处理 r.Result ...
}与 ContinueOnError 的区别
Config.ContinueOnError 字段控制的是 SetMultiple 的中途容错(某条路径写入失败时是否继续写其余路径),并不作用于 ProcessBatch。ProcessBatch 的逐操作隔离是内置行为,无需也无法通过该开关关闭。
实战场景:批量数据迁移
将一批记录统一加上迁移标记,一次 ProcessBatch 调用完成全部转换,并收集每条记录的输出:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
// 模拟从数据源读取的多条记录
records := []string{
`{"id":1,"name":"Alice","age":30}`,
`{"id":2,"name":"Bob","age":25}`,
`{"id":3,"name":"CyberGo","age":28}`,
}
// 为每条记录生成一个 set 操作,统一打上迁移标记
ops := make([]json.BatchOperation, len(records))
for i, r := range records {
ops[i] = json.BatchOperation{
Type: "set",
JSONStr: r,
Path: "migrated",
Value: true,
ID: fmt.Sprintf("record-%d", i),
}
}
results, err := json.ProcessBatch(ops)
if err != nil {
panic(err)
}
for _, r := range results {
if r.Error != nil {
fmt.Printf("%s 失败: %v\n", r.ID, r.Error)
continue
}
fmt.Printf("%s -> %s\n", r.ID, r.Result)
}
}
// 输出:
// record-0 -> {"age":30,"id":1,"migrated":true,"name":"Alice"}
// record-1 -> {"age":25,"id":2,"migrated":true,"name":"Bob"}
// record-2 -> {"age":28,"id":3,"migrated":true,"name":"CyberGo"}缓存预热 WarmupCache
签名:func WarmupCache(jsonStr string, paths []string, cfg ...Config) (*WarmupResult, error)
对同一份 JSON 的热点路径预先求值并填入缓存,使后续首次 Get 直接命中缓存。要求处理器开启缓存(默认开启),否则返回 ErrCacheDisabled。
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
data := `{"user":{"name":"CyberGo","age":25},"meta":{"version":2}}`
result, err := json.WarmupCache(data, []string{"user.name", "user.age", "meta.version"})
if err != nil {
panic(err)
}
fmt.Printf("预热:%d/%d 成功(%.0f%%)\n", result.Successful, result.TotalPaths, result.SuccessRate)
// 预热后首次 Get 命中缓存
name, err := json.Get(data, "user.name")
if err != nil {
panic(err)
}
fmt.Println("name:", name)
}
// 输出:
// 预热:3/3 成功(100%)
// name: CyberGoWarmupResult 结构:
| 字段 | 类型 | 说明 |
|---|---|---|
TotalPaths | int | 待预热路径总数 |
Successful | int | 成功条数 |
Failed | int | 失败条数 |
SuccessRate | float64 | 成功率(百分比) |
FailedPaths | []string | 失败的路径列表(无失败时为 nil) |
当全部路径都失败时,WarmupCache 在返回 WarmupResult 的同时附带最后一个错误。
类型定义
BatchOperation
批量操作描述结构。
type BatchOperation struct {
Type string `json:"type"` // 操作类型:"get", "set", "delete", "validate"
JSONStr string `json:"json_str"` // 目标 JSON 字符串
Path string `json:"path"` // 路径表达式
Value any `json:"value"` // 操作值(set 操作使用)
ID string `json:"id"` // 操作标识
}BatchResult
批量操作结果结构。
type BatchResult struct {
ID string `json:"id"` // 操作标识
Result any `json:"result"` // 操作结果(含义随 Type 变化,见上表)
Error error `json:"error"` // 错误信息(单操作级别)
}Processor 批量方法
Processor 实例提供等价的批量方法 p.ProcessBatch(operations),签名与包级函数一致,适合复用 Processor、或需要按 Config 定制(如 Pretty 输出、PreserveNumbers)的场景。详见 Processor 批量操作。
相关
- 修改函数 - Set, SetMultiple, MergeJSON 等修改操作
- Processor 批量操作 - Processor 级批量操作方法详解
- 辅助工具 - WarmupCache、ClearCache、GetStats 等工具函数