What it is
GJSON reads values from JSON with a dot-notation path syntax, without defining structs or unmarshalling the whole document.
Query with paths such as `books.0.title` or `books.#(year>1990)#.title`. GJSON scans rather than parsing the whole document, so it is fast for selective reads.
Installation
go get -u github.com/tidwall/gjsonGetting started
The smallest useful thing you can do with it, and what each part means.
go
const data = `{"books":[
{"title":"Dune","year":1965,"tags":["scifi"]},
{"title":"Neuromancer","year":1984}
]}`
gjson.Get(data, "books.0.title").String() // Dune
gjson.Get(data, "books.#").Int() // 2 (count)
gjson.Get(data, "books.#.title").Array() // [Dune Neuromancer]
// Filter, then project.
gjson.Get(data, `books.#(year>1970)#.title`) // [Neuromancer]
if r := gjson.Get(data, "books.0.missing"); !r.Exists() {
// Exists() distinguishes absent from a legitimate zero value.
}Advanced usage
Where the library earns its place over a simpler alternative.
go
if !gjson.Valid(payload) {
return errors.New("invalid json") // Get on invalid JSON has undefined results
}
gjson.Get(payload, "books").ForEach(func(_, value gjson.Result) bool {
title := value.Get("title").String()
year := value.Get("year").Int()
process(title, year)
return true // return false to stop early
})Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Empty results from a valid-looking path
- Check Exists(). Array indices are zero-based and `#` is the count operator, not an index.
- Nonsense values from malformed JSON
- GJSON assumes well-formed input for speed. Guard with gjson.Valid.
Best practices
- Call gjson.Valid on untrusted input before querying it.
- Use Result.Exists() rather than comparing against the zero value.
- Prefer encoding/json with a struct when you need the whole document — GJSON wins on selective reads.
- Pair with sjson when you also need to set values without a full round trip.
Background
Why it exists, and what it was reacting to.
Written by Josh Baker, GJSON targets the case where you need three fields out of a large JSON payload and defining a matching struct would be pure overhead.
