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"],
|
||||
"fav.movie": "Deer Hunter",
|
||||
"friends": [
|
||||
{"first": "James", "last": "Murphy"},
|
||||
{"first": "Roger", "last": "Craig"}
|
||||
{"first": "Dale", "last": "Murphy"},
|
||||
{"first": "Roger", "last": "Craig"},
|
||||
{"first": "Jane", "last": "Murphy"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
@ -80,12 +81,16 @@ The dot and wildcard characters can be escaped with '\'.
|
|||
"child*.2" >> "Jack"
|
||||
"c?ildren.0" >> "Sara"
|
||||
"fav\.movie" >> "Deer Hunter"
|
||||
"friends.#.first" >> ["James","Roger"]
|
||||
"friends.#.first" >> ["Dale","Roger","Jane"]
|
||||
"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
|
||||
|
|
26
gjson.go
26
gjson.go
|
@ -554,6 +554,7 @@ type arrayPathResult struct {
|
|||
path string
|
||||
op string
|
||||
value string
|
||||
all bool
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -644,6 +645,9 @@ func parseArrayPath(path string) (r arrayPathResult) {
|
|||
}
|
||||
}
|
||||
} else if path[i] == ']' {
|
||||
if i+1 < len(path) && path[i+1] == '#' {
|
||||
r.query.all = true
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -975,6 +979,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
|||
var h int
|
||||
var alog []int
|
||||
var partidx int
|
||||
var multires []byte
|
||||
rp := parseArrayPath(path)
|
||||
if !rp.arrch {
|
||||
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)
|
||||
if queryMatches(&rp, res) {
|
||||
if rp.more {
|
||||
c.value = Get(val, rp.path)
|
||||
res = Get(val, rp.path)
|
||||
} else {
|
||||
c.value.Raw = val
|
||||
c.value.Type = JSON
|
||||
res = Result{Raw: val, 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
|
||||
}
|
||||
}
|
||||
} else if hit {
|
||||
if rp.alogok {
|
||||
break
|
||||
|
@ -1123,6 +1137,12 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
|
|||
return i + 1, true
|
||||
}
|
||||
}
|
||||
if len(multires) > 0 && !c.value.Exists() {
|
||||
c.value = Result{
|
||||
Raw: string(append(multires, ']')),
|
||||
Type: JSON,
|
||||
}
|
||||
}
|
||||
return i + 1, false
|
||||
}
|
||||
break
|
||||
|
|
|
@ -107,17 +107,20 @@ var basicJSON = `{"age":100, "name":{"here":"B\\\"R"},
|
|||
{
|
||||
"firstName": "Brett",
|
||||
"lastName": "McLaughlin",
|
||||
"email": "aaaa"
|
||||
"email": "aaaa",
|
||||
"tag": "good"
|
||||
},
|
||||
{
|
||||
"firstName": "Jason",
|
||||
"lastName": "Hunter",
|
||||
"email": "bbbb"
|
||||
"email": "bbbb",
|
||||
"tag": "bad"
|
||||
},
|
||||
{
|
||||
"firstName": "Elliotte",
|
||||
"lastName": "Harold",
|
||||
"email": "cccc"
|
||||
"email": "cccc",
|
||||
"tag":, "good"
|
||||
},
|
||||
{
|
||||
"firstName": 1002.3,
|
||||
|
@ -152,10 +155,17 @@ func get(json, path string) Result {
|
|||
|
||||
func TestBasic(t *testing.T) {
|
||||
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`)
|
||||
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`)
|
||||
|
|
Loading…
Reference in New Issue