README.md

  1<p align="center">
  2<picture>
  3  <source media="(prefers-color-scheme: dark)" srcset="/.github/images/logo-dark.png">
  4  <source media="(prefers-color-scheme: light)" srcset="/.github/images/logo-light.png">
  5  <img src="/.github/images/logo-light.png" width="240" alt="GJSON" >
  6</picture>
  7<br>
  8<a href="https://godoc.org/github.com/tidwall/gjson"><img src="https://img.shields.io/badge/api-reference-blue.svg?style=flat-square" alt="GoDoc"></a>
  9<a href="https://tidwall.com/gjson-play"><img src="https://img.shields.io/badge/%F0%9F%8F%90-playground-9900cc.svg?style=flat-square" alt="GJSON Playground"></a>
 10<a href="SYNTAX.md"><img src="https://img.shields.io/badge/{}-syntax-33aa33.svg?style=flat-square" alt="GJSON Syntax"></a>
 11	
 12</p>
 13
 14<p align="center">get json values quickly</a></p>
 15
 16GJSON is a Go package that provides a [fast](#performance) and [simple](#get-a-value) way to get values from a json document.
 17It has features such as [one line retrieval](#get-a-value), [dot notation paths](#path-syntax), [iteration](#iterate-through-an-object-or-array), and [parsing json lines](#json-lines).
 18
 19Also check out [SJSON](https://github.com/tidwall/sjson) for modifying json, and the [JJ](https://github.com/tidwall/jj) command line tool.
 20
 21This README is a quick overview of how to use GJSON, for more information check out [GJSON Syntax](SYNTAX.md).
 22
 23GJSON is also available for [Python](https://github.com/volans-/gjson-py) and [Rust](https://github.com/tidwall/gjson.rs)
 24
 25Getting Started
 26===============
 27
 28## Installing
 29
 30To start using GJSON, install Go and run `go get`:
 31
 32```sh
 33$ go get -u github.com/tidwall/gjson
 34```
 35
 36This will retrieve the library.
 37
 38## Get a value
 39Get searches json for the specified path. A path is in dot syntax, such as "name.last" or "age". When the value is found it's returned immediately. 
 40
 41```go
 42package main
 43
 44import "github.com/tidwall/gjson"
 45
 46const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
 47
 48func main() {
 49	value := gjson.Get(json, "name.last")
 50	println(value.String())
 51}
 52```
 53
 54This will print:
 55
 56```
 57Prichard
 58```
 59*There's also the [GetMany](#get-multiple-values-at-once) function to get multiple values at once, and [GetBytes](#working-with-bytes) for working with JSON byte slices.*
 60
 61## Path Syntax
 62
 63Below is a quick overview of the path syntax, for more complete information please
 64check out [GJSON Syntax](SYNTAX.md).
 65
 66A path is a series of keys separated by a dot.
 67A key may contain special wildcard characters '\*' and '?'.
 68To access an array value use the index as the key.
 69To get the number of elements in an array or to access a child path, use the '#' character.
 70The dot and wildcard characters can be escaped with '\\'.
 71
 72```json
 73{
 74  "name": {"first": "Tom", "last": "Anderson"},
 75  "age":37,
 76  "children": ["Sara","Alex","Jack"],
 77  "fav.movie": "Deer Hunter",
 78  "friends": [
 79    {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
 80    {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
 81    {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}
 82  ]
 83}
 84```
 85```
 86"name.last"          >> "Anderson"
 87"age"                >> 37
 88"children"           >> ["Sara","Alex","Jack"]
 89"children.#"         >> 3
 90"children.1"         >> "Alex"
 91"child*.2"           >> "Jack"
 92"c?ildren.0"         >> "Sara"
 93"fav\.movie"         >> "Deer Hunter"
 94"friends.#.first"    >> ["Dale","Roger","Jane"]
 95"friends.1.last"     >> "Craig"
 96```
 97
 98You can also query an array for the first match by using `#(...)`, or find all 
 99matches with `#(...)#`. Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` 
100comparison operators and the simple pattern matching `%` (like) and `!%` 
101(not like) operators.
102
103```
104friends.#(last=="Murphy").first    >> "Dale"
105friends.#(last=="Murphy")#.first   >> ["Dale","Jane"]
106friends.#(age>45)#.last            >> ["Craig","Murphy"]
107friends.#(first%"D*").last         >> "Murphy"
108friends.#(first!%"D*").last        >> "Craig"
109friends.#(nets.#(=="fb"))#.first   >> ["Dale","Roger"]
110```
111
112*Please note that prior to v1.3.0, queries used the `#[...]` brackets. This was
113changed in v1.3.0 as to avoid confusion with the new
114[multipath](SYNTAX.md#multipaths) syntax. For backwards compatibility, 
115`#[...]` will continue to work until the next major release.*
116
117## Result Type
118
119GJSON supports the json types `string`, `number`, `bool`, and `null`. 
120Arrays and Objects are returned as their raw json types. 
121
122The `Result` type holds one of these:
123
124```
125bool, for JSON booleans
126float64, for JSON numbers
127string, for JSON string literals
128nil, for JSON null
129```
130
131To directly access the value:
132
133```go
134result.Type           // can be String, Number, True, False, Null, or JSON
135result.Str            // holds the string
136result.Num            // holds the float64 number
137result.Raw            // holds the raw json
138result.Index          // index of raw value in original json, zero means index unknown
139result.Indexes        // indexes of all the elements that match on a path containing the '#' query character.
140```
141
142There are a variety of handy functions that work on a result:
143
144```go
145result.Exists() bool
146result.Value() interface{}
147result.Int() int64
148result.Uint() uint64
149result.Float() float64
150result.String() string
151result.Bool() bool
152result.Time() time.Time
153result.Array() []gjson.Result
154result.Map() map[string]gjson.Result
155result.Get(path string) Result
156result.ForEach(iterator func(key, value Result) bool)
157result.Less(token Result, caseSensitive bool) bool
158```
159
160The `result.Value()` function returns an `interface{}` which requires type assertion and is one of the following Go types:
161
162```go
163boolean >> bool
164number  >> float64
165string  >> string
166null    >> nil
167array   >> []interface{}
168object  >> map[string]interface{}
169```
170
171The `result.Array()` function returns back an array of values.
172If the result represents a non-existent value, then an empty array will be returned.
173If the result is not a JSON array, the return value will be an array containing one result.
174
175### 64-bit integers
176
177The `result.Int()` and `result.Uint()` calls are capable of reading all 64 bits, allowing for large JSON integers.
178
179```go
180result.Int() int64    // -9223372036854775808 to 9223372036854775807
181result.Uint() uint64   // 0 to 18446744073709551615
182```
183
184## Modifiers and path chaining 
185
186New in version 1.2 is support for modifier functions and path chaining.
187
188A modifier is a path component that performs custom processing on the 
189json.
190
191Multiple paths can be "chained" together using the pipe character. 
192This is useful for getting results from a modified query.
193
194For example, using the built-in `@reverse` modifier on the above json document,
195we'll get `children` array and reverse the order:
196
197```
198"children|@reverse"           >> ["Jack","Alex","Sara"]
199"children|@reverse|0"         >> "Jack"
200```
201
202There are currently the following built-in modifiers:
203
204- `@reverse`: Reverse an array or the members of an object.
205- `@ugly`: Remove all whitespace from a json document.
206- `@pretty`: Make the json document more human readable.
207- `@this`: Returns the current element. It can be used to retrieve the root element.
208- `@valid`: Ensure the json document is valid.
209- `@flatten`: Flattens an array.
210- `@join`: Joins multiple objects into a single object.
211- `@keys`: Returns an array of keys for an object.
212- `@values`: Returns an array of values for an object.
213- `@tostr`: Converts json to a string. Wraps a json string.
214- `@fromstr`: Converts a string from json. Unwraps a json string.
215- `@group`: Groups arrays of objects. See [e4fc67c](https://github.com/tidwall/gjson/commit/e4fc67c92aeebf2089fabc7872f010e340d105db).
216- `@dig`: Search for a value without providing its entire path. See [e8e87f2](https://github.com/tidwall/gjson/commit/e8e87f2a00dc41f3aba5631094e21f59a8cf8cbf).
217
218### Modifier arguments
219
220A modifier may accept an optional argument. The argument can be a valid JSON 
221document or just characters.
222
223For example, the `@pretty` modifier takes a json object as its argument. 
224
225```
226@pretty:{"sortKeys":true} 
227```
228
229Which makes the json pretty and orders all of its keys.
230
231```json
232{
233  "age":37,
234  "children": ["Sara","Alex","Jack"],
235  "fav.movie": "Deer Hunter",
236  "friends": [
237    {"age": 44, "first": "Dale", "last": "Murphy"},
238    {"age": 68, "first": "Roger", "last": "Craig"},
239    {"age": 47, "first": "Jane", "last": "Murphy"}
240  ],
241  "name": {"first": "Tom", "last": "Anderson"}
242}
243```
244
245*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`. 
246Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*
247
248### Custom modifiers
249
250You can also add custom modifiers.
251
252For example, here we create a modifier that makes the entire json document upper
253or lower case.
254
255```go
256gjson.AddModifier("case", func(json, arg string) string {
257  if arg == "upper" {
258    return strings.ToUpper(json)
259  }
260  if arg == "lower" {
261    return strings.ToLower(json)
262  }
263  return json
264})
265```
266
267```
268"children|@case:upper"           >> ["SARA","ALEX","JACK"]
269"children|@case:lower|@reverse"  >> ["jack","alex","sara"]
270```
271
272## JSON Lines
273
274There's support for [JSON Lines](http://jsonlines.org/) using the `..` prefix, which treats a multilined document as an array. 
275
276For example:
277
278```
279{"name": "Gilbert", "age": 61}
280{"name": "Alexa", "age": 34}
281{"name": "May", "age": 57}
282{"name": "Deloise", "age": 44}
283```
284
285```
286..#                   >> 4
287..1                   >> {"name": "Alexa", "age": 34}
288..3                   >> {"name": "Deloise", "age": 44}
289..#.name              >> ["Gilbert","Alexa","May","Deloise"]
290..#(name="May").age   >> 57
291```
292
293The `ForEachLines` function will iterate through JSON lines.
294
295```go
296gjson.ForEachLine(json, func(line gjson.Result) bool{
297    println(line.String())
298    return true
299})
300```
301
302## Get nested array values
303
304Suppose you want all the last names from the following json:
305
306```json
307{
308  "programmers": [
309    {
310      "firstName": "Janet", 
311      "lastName": "McLaughlin", 
312    }, {
313      "firstName": "Elliotte", 
314      "lastName": "Hunter", 
315    }, {
316      "firstName": "Jason", 
317      "lastName": "Harold", 
318    }
319  ]
320}
321```
322
323You would use the path "programmers.#.lastName" like such:
324
325```go
326result := gjson.Get(json, "programmers.#.lastName")
327for _, name := range result.Array() {
328	println(name.String())
329}
330```
331
332You can also query an object inside an array:
333
334```go
335name := gjson.Get(json, `programmers.#(lastName="Hunter").firstName`)
336println(name.String())  // prints "Elliotte"
337```
338
339## Iterate through an object or array
340
341The `ForEach` function allows for quickly iterating through an object or array. 
342The key and value are passed to the iterator function for objects.
343Only the value is passed for arrays.
344Returning `false` from an iterator will stop iteration.
345
346```go
347result := gjson.Get(json, "programmers")
348result.ForEach(func(key, value gjson.Result) bool {
349	println(value.String()) 
350	return true // keep iterating
351})
352```
353
354## Simple Parse and Get
355
356There's a `Parse(json)` function that will do a simple parse, and `result.Get(path)` that will search a result.
357
358For example, all of these will return the same result:
359
360```go
361gjson.Parse(json).Get("name").Get("last")
362gjson.Get(json, "name").Get("last")
363gjson.Get(json, "name.last")
364```
365
366## Check for the existence of a value
367
368Sometimes you just want to know if a value exists. 
369
370```go
371value := gjson.Get(json, "name.last")
372if !value.Exists() {
373	println("no last name")
374} else {
375	println(value.String())
376}
377
378// Or as one step
379if gjson.Get(json, "name.last").Exists() {
380	println("has a last name")
381}
382```
383
384## Validate JSON
385
386The `Get*` and `Parse*` functions expects that the json is well-formed. Bad json will not panic, but it may return back unexpected results.
387
388If you are consuming JSON from an unpredictable source then you may want to validate prior to using GJSON.
389
390```go
391if !gjson.Valid(json) {
392	return errors.New("invalid json")
393}
394value := gjson.Get(json, "name.last")
395```
396
397## Unmarshal to a map
398
399To unmarshal to a `map[string]interface{}`:
400
401```go
402m, ok := gjson.Parse(json).Value().(map[string]interface{})
403if !ok {
404	// not a map
405}
406```
407
408## Working with Bytes
409
410If your JSON is contained in a `[]byte` slice, there's the [GetBytes](https://godoc.org/github.com/tidwall/gjson#GetBytes) function. This is preferred over `Get(string(data), path)`.
411
412```go
413var json []byte = ...
414result := gjson.GetBytes(json, path)
415```
416
417If you are using the `gjson.GetBytes(json, path)` function and you want to avoid converting `result.Raw` to a `[]byte`, then you can use this pattern:
418
419```go
420var json []byte = ...
421result := gjson.GetBytes(json, path)
422var raw []byte
423if result.Index > 0 {
424    raw = json[result.Index:result.Index+len(result.Raw)]
425} else {
426    raw = []byte(result.Raw)
427}
428```
429
430This is a best-effort no allocation sub slice of the original json. This method utilizes the `result.Index` field, which is the position of the raw data in the original json. It's possible that the value of `result.Index` equals zero, in which case the `result.Raw` is converted to a `[]byte`.
431
432## Performance
433
434Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/), 
435[ffjson](https://github.com/pquerna/ffjson), 
436[EasyJSON](https://github.com/mailru/easyjson),
437[jsonparser](https://github.com/buger/jsonparser),
438and [json-iterator](https://github.com/json-iterator/go)
439
440```
441BenchmarkGJSONGet-10             17893731    202.1 ns/op      0 B/op     0 allocs/op
442BenchmarkGJSONUnmarshalMap-10     1663548   2157 ns/op     1920 B/op    26 allocs/op
443BenchmarkJSONUnmarshalMap-10       832236   4279 ns/op     2920 B/op    68 allocs/op
444BenchmarkJSONUnmarshalStruct-10   1076475   3219 ns/op      920 B/op    12 allocs/op
445BenchmarkJSONDecoder-10            585729   6126 ns/op     3845 B/op   160 allocs/op
446BenchmarkFFJSONLexer-10           2508573   1391 ns/op      880 B/op     8 allocs/op
447BenchmarkEasyJSONLexer-10         3000000    537.9 ns/op    501 B/op     5 allocs/op
448BenchmarkJSONParserGet-10        13707510    263.9 ns/op     21 B/op     0 allocs/op
449BenchmarkJSONIterator-10          3000000    561.2 ns/op    693 B/op    14 allocs/op
450```
451
452JSON document used:
453
454```json
455{
456  "widget": {
457    "debug": "on",
458    "window": {
459      "title": "Sample Konfabulator Widget",
460      "name": "main_window",
461      "width": 500,
462      "height": 500
463    },
464    "image": { 
465      "src": "Images/Sun.png",
466      "hOffset": 250,
467      "vOffset": 250,
468      "alignment": "center"
469    },
470    "text": {
471      "data": "Click Here",
472      "size": 36,
473      "style": "bold",
474      "vOffset": 100,
475      "alignment": "center",
476      "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
477    }
478  }
479}    
480```
481
482Each operation was rotated through one of the following search paths:
483
484```
485widget.window.name
486widget.image.hOffset
487widget.text.onMouseUp
488```
489
490**
491
492*These benchmarks were run on a MacBook Pro M1 Max using Go 1.22 and can be found [here](https://github.com/tidwall/gjson-benchmarks).*