Skip to content

批量操作函数

json 包提供的批量操作函数,支持一次性处理多个 JSON 操作(get/set/delete/validate),适合批量数据处理场景。

ProcessBatch

签名:func ProcessBatch(operations []BatchOperation, cfg ...Config) ([]BatchResult, error)

批量处理多个 JSON 操作(包级函数,无需创建 Processor)。返回结果顺序与输入操作顺序一一对应,通过 ID 字段关联。

go
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读取路径上的值路径处的值(anyErrPathNotFoundErrInvalidJSON
set设置路径的值修改后的完整 JSON 字符串ErrPathNotFound(未开 CreatePaths)、ErrInvalidPath
delete删除路径上的节点删除后的完整 JSON 字符串ErrPathNotFoundErrInvalidPath
validate验证 JSON 是否合法map[string]any{"valid": bool}无效 JSON 时 Result.valid=falseError 非空

操作互不链式

每个 BatchOperation独立作用于各自的 JSONStr 输入,操作之间不会链式叠加。例如对同一文档先 setdelete,得到的是两个独立结果,而不是「先改再删」的叠加态。若需对单个文档做多步变换,请在代码中将上一步的输出喂给下一步,或改用 SetMultiple 等单文档多路径方法。

批量大小限制

操作数量受 Config.MaxBatchSize 约束(默认 2000)。超出时整个批次直接失败,返回 (nil, ErrSizeLimit)

go
// 自定义上限(适用于超大批量场景)
cfg := json.DefaultConfig()
cfg.MaxBatchSize = 5000
results, err := json.ProcessBatch(ops, cfg)

各操作类型示例

get — 批量读取

get 操作的 Result 是路径处的原始值(数字默认为 float64,布尔为 bool,字符串为 string)。

go
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 = true

set — 批量修改

set 操作的 Result修改后的完整 JSON 字符串(注意不是写入的值本身)。默认配置 CreatePaths=true,因此设置新路径会自动创建中间节点。

go
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 字符串

go
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 非法时 validfalseError 携带解析错误。

go
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

go
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 的中途容错(某条路径写入失败时是否继续写其余路径),并不作用于 ProcessBatchProcessBatch 的逐操作隔离是内置行为,无需也无法通过该开关关闭。

实战场景:批量数据迁移

将一批记录统一加上迁移标记,一次 ProcessBatch 调用完成全部转换,并收集每条记录的输出:

go
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

go
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: CyberGo

WarmupResult 结构:

字段类型说明
TotalPathsint待预热路径总数
Successfulint成功条数
Failedint失败条数
SuccessRatefloat64成功率(百分比)
FailedPaths[]string失败的路径列表(无失败时为 nil)

当全部路径都失败时,WarmupCache 在返回 WarmupResult 的同时附带最后一个错误。

类型定义

BatchOperation

批量操作描述结构。

go
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

批量操作结果结构。

go
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 批量操作

相关