# GJSON Path Syntax

A GJSON Path is a text string syntax that describes a search pattern for quickly retreiving values from a JSON payload.

This document is designed to explain the structure of a GJSON Path through examples.

- [Path structure](#path-structure)
- [Basic](#basic)
- [Wildcards](#wildcards)
- [Escape Character](#escape-character)
- [Arrays](#arrays)
- [Queries](#queries)
- [Dot vs Pipe](#dot-vs-pipe)
- [Modifiers](#modifiers)

The definitive implemenation is [github.com/tidwall/gjson](https://github.com/tidwall/gjson).


## Path structure

A GJSON Path is intended to be easily expressed as a series of components seperated by a `.` character. 

Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, and `?`.

## Example

Given this JSON

```json
{
  "name": {"first": "Tom", "last": "Anderson"},
  "age":37,
  "children": ["Sara","Alex","Jack"],
  "fav.movie": "Deer Hunter",
  "friends": [
    {"first": "Dale", "last": "Murphy", "age": 44},
    {"first": "Roger", "last": "Craig", "age": 68},
    {"first": "Jane", "last": "Murphy", "age": 47}
  ]
}
```

The following GJSON Paths evaluate to the accompanying values.

### Basic 

In many cases you'll just want to retreive values by object name or array index.

```go
name.last              "Anderson"
name.first             "Tom"
age                    37
children               ["Sara","Alex","Jack"]
children.0             "Sara"
children.1             "Alex"
friends.1              {"first": "Roger", "last": "Craig", "age": 68}
friends.1.first        "Roger"
```

### Wildcards

A key may contain the special wildcard characters `*` and `?`. 
The `*` will match on any zero+ characters, and `?` matches on any one character.

```go
child*.2               "Jack"
c?ildren.0             "Sara"
```

### Escape character

Special purpose characters, such as `.`, `*`, and `?` can be escaped with `\`. 

```go
fav\.movie             "Deer Hunter"
```


### Arrays

The `#` character allows for digging into JSON Arrays.

To get the length of an array you'll just use the `#` all by itself.

```go
friends.#              3
friends.#.age         [44,68,47]
```

### Queries

You can also query an array for the first match by  using `#[...]`, or find all matches with `#[...]#`. 
Queries support the `==`, `!=`, `<`, `<=`, `>`, `>=` comparison operators, 
and the simple pattern matching `%` (like) and `!%` (not like) operators.

```go
friends.#[last=="Murphy"].first     "Dale"
friends.#[last=="Murphy"]#.first    ["Dale","Jane"]
friends.#[age>45]#.last             ["Craig","Murphy"]
friends.#[first%"D*"].last          "Murphy"
friends.#[first!%"D*"].last         "Craig"
```

To query for a non-object value in an array, you can forgo the string to the right of the operator.
```go
children.#[!%"*a*"]                 "Alex"
children.#[%"*a*"]#                 ["Sara","Jack"]
```



### Dot vs Pipe

The `.` is standard separator, but it's also possible to use a `|`. 
In most cases they both end up returning the same results.
The cases where`|` differs from `.` is when it's used after the `#` for [Arrays](#arrays) and [Queries](#queries). 

Here are some examples

```go
friends.0.first                     "Dale"
friends|0.first                     "Dale"
friends.0|first                     "Dale"
friends|0|first                     "Dale"
friends|#                           3
friends.#                           3
friends.#[last="Murphy"]#           [{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
friends.#[last="Murphy"]#.first     ["Dale","Jane"]
friends.#[last="Murphy"]#|first     <non-existent>
friends.#[last="Murphy"]#.0         []
friends.#[last="Murphy"]#|0         {"first": "Dale", "last": "Murphy", "age": 44}
friends.#[last="Murphy"]#.#         []
friends.#[last="Murphy"]#|#         2
```

Let's break down a few of these.

The path `friends.#[last="Murphy"]#` all by itself results in

```json
[{"first": "Dale", "last": "Murphy", "age": 44},{"first": "Jane", "last": "Murphy", "age": 47}]
```

The `.first` suffix will process the `first` path on each array element *before* returning the results. Which becomes

```json
["Dale","Jane"]
```

But the `|first` suffix actually processes the `first` path *after* the previous result. 
Since the previous result is an array, not an object, it's not possible to process 
because `first` does not exist.

Yet, `|0` suffix returns

```json
{"first": "Dale", "last": "Murphy", "age": 44}
```

Because `0` is the first index of the previous result.

### Modifiers

A modifier is a path component that performs custom processing on the JSON.

For example, using the built-in `@reverse` modifier on the above JSON payload will reverse the `children` array:

```go
children.@reverse                   ["Jack","Alex","Sara"]
children.@reverse.0                 "Jack"
```

There are currently three built-in modifiers:

- `@reverse`: Reverse an array or the members of an object.
- `@ugly`: Remove all whitespace from JSON.
- `@pretty`: Make the JSON more human readable.

#### Modifier arguments

A modifier may accept an optional argument. The argument can be a valid JSON payload or just characters.

For example, the `@pretty` modifier takes a json object as its argument.

```
@pretty:{"sortKeys":true}
```

Which makes the json pretty and orders all of its keys.

```json
{
  "age":37,
  "children": ["Sara","Alex","Jack"],
  "fav.movie": "Deer Hunter",
  "friends": [
    {"age": 44, "first": "Dale", "last": "Murphy"},
    {"age": 68, "first": "Roger", "last": "Craig"},
    {"age": 47, "first": "Jane", "last": "Murphy"}
  ],
  "name": {"first": "Tom", "last": "Anderson"}
}
```

*The full list of `@pretty` options are `sortKeys`, `indent`, `prefix`, and `width`. 
Please see [Pretty Options](https://github.com/tidwall/pretty#customized-output) for more information.*

#### Custom modifiers

You can also add custom modifiers. 

For example, here we create a modifier which makes the entire JSON payload upper or lower case.

```go
gjson.AddModifier("case", func(json, arg string) string {
  if arg == "upper" {
    return strings.ToUpper(json)
  }
  if arg == "lower" {
    return strings.ToLower(json)
  }
  return json
})
"children.@case:upper"             ["SARA","ALEX","JACK"]
"children.@case:lower.@reverse"    ["jack","alex","sara"]
```

