mirror of https://github.com/tidwall/gjson.git
Query array for multiple matches
It's now possible to query an array for multiple matches by adding the '#' character immediately following the query. For example, using the following JSON: { "friends": [ {"first": "Dale", "last": "Murphy"}, {"first": "Roger", "last": "Craig"}, {"first": "Jane", "last": "Murphy"} ] } To return the first match: `friends.#[last="Murphy"].first` >> "Dale" To return all matches: `friends.#[last="Murphy"]#.first` >> ["Dale","Jane"] Thanks to @chuttam for requesting this feature, closes #15.
This commit is contained in:
parent
1303e83611
commit
86b1b630e4
15
README.md
15
README.md
|
@ -66,8 +66,9 @@ The dot and wildcard characters can be escaped with '\'.
|
||||||
"children": ["Sara","Alex","Jack"],
|
"children": ["Sara","Alex","Jack"],
|
||||||
"fav.movie": "Deer Hunter",
|
"fav.movie": "Deer Hunter",
|
||||||
"friends": [
|
"friends": [
|
||||||
{"first": "James", "last": "Murphy"},
|
{"first": "Dale", "last": "Murphy"},
|
||||||
{"first": "Roger", "last": "Craig"}
|
{"first": "Roger", "last": "Craig"},
|
||||||
|
{"first": "Jane", "last": "Murphy"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -80,12 +81,16 @@ The dot and wildcard characters can be escaped with '\'.
|
||||||
"child*.2" >> "Jack"
|
"child*.2" >> "Jack"
|
||||||
"c?ildren.0" >> "Sara"
|
"c?ildren.0" >> "Sara"
|
||||||
"fav\.movie" >> "Deer Hunter"
|
"fav\.movie" >> "Deer Hunter"
|
||||||
"friends.#.first" >> ["James","Roger"]
|
"friends.#.first" >> ["Dale","Roger","Jane"]
|
||||||
"friends.1.last" >> "Craig"
|
"friends.1.last" >> "Craig"
|
||||||
```
|
```
|
||||||
To query an array:
|
To query an array for the first match:
|
||||||
```
|
```
|
||||||
`friends.#[last="Murphy"].first` >> "James"
|
`friends.#[last="Murphy"].first` >> "Dale"
|
||||||
|
```
|
||||||
|
To query an array for all matches:
|
||||||
|
```
|
||||||
|
`friends.#[last="Murphy"]#.first` >> ["Dale","Jane"]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Result Type
|
## Result Type
|
||||||
|
|
26
gjson.go
26
gjson.go
|
@ -554,6 +554,7 @@ type arrayPathResult struct {
|
||||||
path string
|
path string
|
||||||
op string
|
op string
|
||||||
value string
|
value string
|
||||||
|
all bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,6 +645,9 @@ func parseArrayPath(path string) (r arrayPathResult) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if path[i] == ']' {
|
} else if path[i] == ']' {
|
||||||
|
if i+1 < len(path) && path[i+1] == '#' {
|
||||||
|
r.query.all = true
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -975,6 +979,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
var h int
|
var h int
|
||||||
var alog []int
|
var alog []int
|
||||||
var partidx int
|
var partidx int
|
||||||
|
var multires []byte
|
||||||
rp := parseArrayPath(path)
|
rp := parseArrayPath(path)
|
||||||
if !rp.arrch {
|
if !rp.arrch {
|
||||||
n, err := strconv.ParseUint(rp.part, 10, 64)
|
n, err := strconv.ParseUint(rp.part, 10, 64)
|
||||||
|
@ -1031,13 +1036,22 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
res := Get(val, rp.query.path)
|
res := Get(val, rp.query.path)
|
||||||
if queryMatches(&rp, res) {
|
if queryMatches(&rp, res) {
|
||||||
if rp.more {
|
if rp.more {
|
||||||
c.value = Get(val, rp.path)
|
res = Get(val, rp.path)
|
||||||
} else {
|
} else {
|
||||||
c.value.Raw = val
|
res = Result{Raw: val, Type: JSON}
|
||||||
c.value.Type = JSON
|
|
||||||
}
|
}
|
||||||
|
if rp.query.all {
|
||||||
|
if len(multires) == 0 {
|
||||||
|
multires = append(multires, '[')
|
||||||
|
} else {
|
||||||
|
multires = append(multires, ',')
|
||||||
|
}
|
||||||
|
multires = append(multires, res.Raw...)
|
||||||
|
} else {
|
||||||
|
c.value = res
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if hit {
|
} else if hit {
|
||||||
if rp.alogok {
|
if rp.alogok {
|
||||||
break
|
break
|
||||||
|
@ -1123,6 +1137,12 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
||||||
return i + 1, true
|
return i + 1, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(multires) > 0 && !c.value.Exists() {
|
||||||
|
c.value = Result{
|
||||||
|
Raw: string(append(multires, ']')),
|
||||||
|
Type: JSON,
|
||||||
|
}
|
||||||
|
}
|
||||||
return i + 1, false
|
return i + 1, false
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
|
@ -107,17 +107,20 @@ var basicJSON = `{"age":100, "name":{"here":"B\\\"R"},
|
||||||
{
|
{
|
||||||
"firstName": "Brett",
|
"firstName": "Brett",
|
||||||
"lastName": "McLaughlin",
|
"lastName": "McLaughlin",
|
||||||
"email": "aaaa"
|
"email": "aaaa",
|
||||||
|
"tag": "good"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"firstName": "Jason",
|
"firstName": "Jason",
|
||||||
"lastName": "Hunter",
|
"lastName": "Hunter",
|
||||||
"email": "bbbb"
|
"email": "bbbb",
|
||||||
|
"tag": "bad"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"firstName": "Elliotte",
|
"firstName": "Elliotte",
|
||||||
"lastName": "Harold",
|
"lastName": "Harold",
|
||||||
"email": "cccc"
|
"email": "cccc",
|
||||||
|
"tag":, "good"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"firstName": 1002.3,
|
"firstName": 1002.3,
|
||||||
|
@ -152,10 +155,17 @@ func get(json, path string) Result {
|
||||||
|
|
||||||
func TestBasic(t *testing.T) {
|
func TestBasic(t *testing.T) {
|
||||||
var mtok Result
|
var mtok Result
|
||||||
|
mtok = get(basicJSON, `loggy.programmers.#[tag="good"].firstName`)
|
||||||
|
if mtok.String() != "Brett" {
|
||||||
|
t.Fatalf("expected %v, got %v", "Brett", mtok.String())
|
||||||
|
}
|
||||||
|
mtok = get(basicJSON, `loggy.programmers.#[tag="good"]#.firstName`)
|
||||||
|
if mtok.String() != `["Brett","Elliotte"]` {
|
||||||
|
t.Fatalf("expected %v, got %v", `["Brett","Elliotte"]`, mtok.String())
|
||||||
|
}
|
||||||
mtok = get(basicJSON, `loggy.programmers.#[age=101].firstName`)
|
mtok = get(basicJSON, `loggy.programmers.#[age=101].firstName`)
|
||||||
if mtok.String() != "1002.3" {
|
if mtok.String() != "1002.3" {
|
||||||
t.Fatalf("expected %v, got %v", "1002,3", mtok.String())
|
t.Fatalf("expected %v, got %v", "1002.3", mtok.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
mtok = get(basicJSON, `loggy.programmers.#[firstName == "Brett"].email`)
|
mtok = get(basicJSON, `loggy.programmers.#[firstName == "Brett"].email`)
|
||||||
|
|
Loading…
Reference in New Issue