tidwall / gjson

Get JSON values quickly - JSON parser for Go
MIT License
13.88k stars 841 forks source link

Retrieve field values with multiple conditions #319

Open ngarg-kr opened 1 year ago

ngarg-kr commented 1 year ago

For a sample payload like this:

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

If we want to get the age of friend whose last name isMurphy and first name is Dale then what gjson expression will give that result.

I tried friends.#(last == "Murphy" && first == "Dale")#.age but it gives an empty array in response.

@tidwall kindly help regarding this

volans- commented 1 year ago

@ngarg-kr you can chain queries for additional fields, so in your case with query:

friends.#(first=="Dale")#|#(last=="Murphy")#.age

you get:

[44]

See https://github.com/tidwall/gjson/blob/master/SYNTAX.md#queries and https://github.com/tidwall/gjson/blob/master/SYNTAX.md#dot-vs-pipe for additional information.

ngarg-kr commented 1 year ago

@volans- Thanks! It worked

sukant-kr commented 1 year ago

@volans- @tidwall

This works for &&(and) condition, can we do something similar for || (or) condition.

Can you please suggest the expression for this:

friends.#(last == "Murphy" || first == "Dale")#.age

volans- commented 1 year ago

@sukant-kr Yes and no, as I've answered in https://github.com/tidwall/gjson/issues/315#issuecomment-1457570374, you can achieve the OR with multipaths and the @flatten modifier, but it would not prevent duplicates if results are matching both queries.

So for example with query:

friends.[#(first=="Dale")#,#(last=="Murphy")#]|@flatten.#.age

you get:

[44,44,47]

Because the first friend matches both queries.

You can at that point either get the parent objects and remove duplicates in your code. Another approach is to avoid them in a query, but it becomes quite complex, basically I'm matching records with:

and putting them together.

Here's the query:

friends.[#(last=="Murphy")#|#(first!="Dale")#,#(last!="Murphy")#|#(first=="Dale")#,#(last=="Murphy")#|#(first=="Dale")#].@flatten.#.age

and you get:

[47,44]
taras-janea commented 1 year ago

Hi @volans-,

Guys, need your help.

package main

import (
    "fmt"

    "github.com/tidwall/gjson"
)

func main() {
    jsonStr := `{
    "points": [
      {"x": 3, "y": 4, "z": 5, "description": "[3, 4, 5]"},
      {"x": 2, "y": 3, "z": 4, "description": "[2, 3, 4]"},
      {"x": 1, "y": 2, "z": 3, "description": "[1, 2, 3]"},
      {"x": 0, "y": 1, "z": 2, "description": "[0, 1, 2]"}
     ]
    }`

    result := gjson.Get(jsonStr, "points.#(x==3)")
    fmt.Println(result.Path(jsonStr))

    result = gjson.Get(jsonStr, "points.#(x==3)#|#(y==4)#|(z==5)")
    fmt.Println(result.Path(jsonStr))
}

Output:

points.0
@this

I desperately need to receive a path to queried result, but it's not returned for the query with multiple values. I expect to receive points.0, but getting @this. How can I query with multiple values and get the path for the result?

Thank you in advance, Taras