Batch Operation Methods
The Processor provides batch capabilities, processing multiple JSON operations (get/set/delete/validate) in a single call. Compared with the package-level ProcessBatch, the Processor form suits instance reuse, or tailoring each batch's behavior via Config (pretty output, number preservation, security limits, etc.).
ProcessBatch
Signature: func (p *Processor) ProcessBatch(operations []BatchOperation, cfg ...Config) ([]BatchResult, error)
Batch-processes multiple JSON operations. Result order matches the input operation order, linked by the ID field.
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
p, err := json.New(json.DefaultConfig())
if err != nil {
panic(err)
}
defer p.Close()
data := `{"user":{"name":"CyberGo","age":25}}`
results, err := p.ProcessBatch([]json.BatchOperation{
{Type: "get", JSONStr: data, Path: "user.name", ID: "name"},
{Type: "set", JSONStr: data, Path: "user.age", Value: 30, ID: "age"},
})
if err != nil {
panic(err)
}
for _, r := range results {
fmt.Printf("%s: %v\n", r.ID, r.Result)
}
}
// Output:
// name: CyberGo
// age: {"user":{"age":30,"name":"CyberGo"}}Supported Operation Types
The Result content and typical errors of the four operation types (get/set/delete/validate), plus the "operations do not chain" semantics, are identical to the package-level function — see the full table in Batch Operations - Supported Operation Types. The Processor-side difference is only in how configuration takes effect (a passed cfg overrides the Processor's own configuration per call; see the next section).
Batch Size Limit
The operation count is bounded by Config.MaxBatchSize (default 2000). The cap applies per call — a passed cfg (if any) overrides the Processor's own configuration. When exceeded, the whole batch fails immediately with (nil, ErrSizeLimit).
Examples per Operation Type
get — batch reads
The Result of a get operation is the raw value at the path (numbers default to float64).
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
p, err := json.New(json.DefaultConfig())
if err != nil {
panic(err)
}
defer p.Close()
data := `{"user":{"name":"CyberGo","age":25}}`
results, err := p.ProcessBatch([]json.BatchOperation{
{Type: "get", JSONStr: data, Path: "user.name", ID: "name"},
{Type: "get", JSONStr: data, Path: "user.age", ID: "age"},
})
if err != nil {
panic(err)
}
for _, r := range results {
fmt.Printf("%s: %v\n", r.ID, r.Result)
}
}
// Output:
// name: CyberGo
// age: 25set — batch modification
The Result of a set is the complete modified JSON string (compact form, object keys sorted lexicographically). The default CreatePaths=true means writing to a new path creates the intermediate nodes automatically:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
p, err := json.New(json.DefaultConfig())
if err != nil {
panic(err)
}
defer p.Close()
data := `{"user":{"name":"CyberGo","age":25}}`
results, err := p.ProcessBatch([]json.BatchOperation{
{Type: "set", JSONStr: data, Path: "user.age", Value: 30, ID: "age"},
{Type: "set", JSONStr: data, Path: "user.role", Value: "admin", ID: "role"},
})
if err != nil {
panic(err)
}
for _, r := range results {
fmt.Printf("%s -> %s\n", r.ID, r.Result)
}
}
// Output:
// age -> {"user":{"age":30,"name":"CyberGo"}}
// role -> {"user":{"age":25,"name":"CyberGo","role":"admin"}}How Config affects the batch
The passed Config is forwarded per operation, but not every field influences the output: set/delete return values are always compact strings (unaffected by Pretty — run the result through Prettify separately if needed); the fields that genuinely take effect per cfg are MaxBatchSize (batch cap), CreatePaths (whether set may create new paths), and PreserveNumbers (affects the number type returned by get: float64 by default, json.Number when enabled).
delete — batch deletion
The Result of a delete is the complete JSON string after deletion.
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
p, err := json.New(json.DefaultConfig())
if err != nil {
panic(err)
}
defer p.Close()
data := `{"user":{"name":"CyberGo","age":25,"temp":"x"},"debug":true}`
results, err := p.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 {
fmt.Printf("%s -> %s\n", r.ID, r.Result)
}
}
// Output:
// drop-temp -> {"debug":true,"user":{"age":25,"name":"CyberGo"}}
// drop-debug -> {"user":{"age":25,"name":"CyberGo","temp":"x"}}validate — batch validation
The Result of a validate is always map[string]any{"valid": bool}; when the JSON is invalid, valid is false and Error carries the parse error.
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
p, err := json.New(json.DefaultConfig())
if err != nil {
panic(err)
}
defer p.Close()
results, err := p.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 error: %v\n", r.ID, r.Error)
}
}
}
// Output:
// ok: valid=true
// broken: valid=false
// broken error: invalid JSON: ...Mixed Operations
A single batch can mix operation types; results come back in order:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
p, err := json.New(json.DefaultConfig())
if err != nil {
panic(err)
}
defer p.Close()
data := `{"user":{"name":"CyberGo"},"processed":false}`
results, err := p.ProcessBatch([]json.BatchOperation{
{Type: "validate", JSONStr: data, ID: "check"},
{Type: "get", JSONStr: data, Path: "user.name", ID: "name"},
{Type: "set", JSONStr: data, Path: "processed", Value: true, ID: "mark"},
})
if err != nil {
panic(err)
}
for _, r := range results {
if r.ID == "check" {
if m, ok := r.Result.(map[string]any); ok {
fmt.Printf("Validation result: %v\n", m["valid"])
}
} else {
fmt.Printf("%s: %v\n", r.ID, r.Result)
}
}
}
// Output:
// Validation result: true
// name: CyberGo
// mark: {"processed":true,"user":{"name":"CyberGo"}}Error Handling and Fault Tolerance
A single failure does not abort the batch
ProcessBatch always processes every operation: a failing operation only sets the Error field of its own result; subsequent operations still run, and no configuration is needed to enable this. Batch results can therefore be "partly successful, partly failed" — always check r.Error entry by entry:
results, err := p.ProcessBatch(operations)
if err != nil {
// err appears only when the processor is closed, the config is invalid,
// or MaxBatchSize is exceeded
return err
}
for _, r := range results {
if r.Error != nil {
log.Printf("Operation %s failed: %v", r.ID, r.Error)
continue
}
// Handle r.Result ...
}Difference from ContinueOnError
The Config.ContinueOnError field governs mid-flight tolerance of SetMultiple (whether to keep writing the remaining paths after one path fails); it does not apply to ProcessBatch. Per-operation isolation in ProcessBatch is built-in — it can be neither enabled nor disabled via that toggle.
Real-World Scenario: Batch Data Migration
Stamp a batch of records with a migration marker, with one ProcessBatch call performing all transformations. The Processor form is especially suitable for long-lived services reusing the same instance across many batches:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
p, err := json.New(json.DefaultConfig())
if err != nil {
panic(err)
}
defer p.Close()
records := []string{
`{"id":1,"name":"Alice","age":30}`,
`{"id":2,"name":"Bob","age":25}`,
`{"id":3,"name":"CyberGo","age":28}`,
}
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 := p.ProcessBatch(ops)
if err != nil {
panic(err)
}
for _, r := range results {
if r.Error != nil {
fmt.Printf("%s failed: %v\n", r.ID, r.Error)
continue
}
fmt.Printf("%s -> %s\n", r.ID, r.Result)
}
}
// Output:
// 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"}Cache Warm-Up: WarmupCache
Signature: func (p *Processor) WarmupCache(jsonStr string, paths []string, cfg ...Config) (*WarmupResult, error)
Pre-evaluates hot paths of the same JSON and fills the cache, so the first subsequent Get hits the cache directly. Requires the Processor's cache to be enabled (it is by default); otherwise returns a JsonsError (Op is warmup_cache, message "cache is disabled, cannot warmup cache").
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
p, err := json.New(json.DefaultConfig())
if err != nil {
panic(err)
}
defer p.Close()
data := `{"user":{"name":"CyberGo","age":25},"meta":{"version":2}}`
result, err := p.WarmupCache(data, []string{"user.name", "user.age", "meta.version"})
if err != nil {
panic(err)
}
fmt.Printf("Warm-up: %d/%d succeeded (%.0f%%)\n", result.Successful, result.TotalPaths, result.SuccessRate)
}
// Output:
// Warm-up: 3/3 succeeded (100%)The WarmupResult struct:
| Field | Type | Description |
|---|---|---|
TotalPaths | int | Total number of paths to warm up |
Successful | int | Successful count |
Failed | int | Failed count |
SuccessRate | float64 | Success rate (percentage) |
FailedPaths | []string | List of failed paths (nil when nothing failed) |
When every path fails, WarmupCache returns the WarmupResult together with the last error.
Type Definitions
BatchOperation Struct
type BatchOperation struct {
Type string `json:"type"` // Operation type: "get", "set", "delete", "validate"
JSONStr string `json:"json_str"` // JSON string
Path string `json:"path"` // Target path
Value any `json:"value"` // Value for Set operations
ID string `json:"id"` // Operation identifier
}BatchResult Struct
type BatchResult struct {
ID string `json:"id"` // Matching operation ID
Result any `json:"result"` // Operation result (meaning varies by Type, see table above)
Error error `json:"error"` // Error of this single operation (does not affect others)
}Notes
- Every operation runs independently; one failure does not affect the others (built-in behavior, no configuration needed)
- Result order matches operation order; match operations and results via
ID MaxBatchSize(default 2000) applies per thecfgof each call; exceeding it fails the whole batch
See Also
- Path Queries - The Get family of methods
- Data Modification - Set/Delete/SetMultiple methods
- Package-Level Batch Operations - ProcessBatch without a Processor