Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
886 views
in Technique[技术] by (71.8m points)

json - Numeric argument passed with jq --arg not matching data with ==

Here is a sample JSON response from my curl:

{
  "success": true,
  "message": "jobStatus",
  "jobStatus": [
    {
      "ID": 9,
      "status": "Successful"
    },
    {
      "ID": 2,
      "status": "Successful"
    },
   {
      "ID": 99,
      "status": "Failed"
    }
  ]
}

I want to check the status of ID=2. Here is the command I tried:

cat test.txt|jq --arg v "2" '.jobStatus[]|select(.ID == $v)|.status'

response: there is none

I tried value 2 without quotes and still no result.

By contrast, if I try the command with a literal 2, it works:

cat test.txt | jq '.jobStatus[]|select(.ID == 2)|.status'

response:

"Successful"

I'm stuck. Can anyone help me identify the problem?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

jq is data-type-aware:

  • .ID, as defined in the JSON input, is a number,

  • but any command-line argument passed with --arg (such as v here) is invariably a string (whether you quote the value or not),

so, in order to compare them, you must use an explicit type conversion, such as with tonumber/1:

jq --arg v '2' '.jobStatus[] | select(.ID == ($v | tonumber)) | .status' test.txt

Given that you're only passing a scalar argument here, the following solution, using --argjson (jq v1.5+) is a bit of an overkill, but it is an alternative to explicit type conversion in that passing a JSON argument in effect passes typed data:

jq --argjson v '{ "ID": 2 }' '.jobStatus[] | select(.ID == $v.ID) | .status' test.txt

peak's answer demonstrates that even --argjson v 2 works (in which case comparing to $v works directly), which is certainly the most concise solution, but may require an explanation:

  • Even though 2 may not look like JSON, it is: it is a valid JSON text containing a single value of type number (see json.org).

    • Specifically, it is the fact that 2 is an unquoted token that starts with a digit that makes it a number in the context of JSON (the JSON string-value equivalent is "2", which from the shell would have to be passed as '"2"' - note the embedded double quotes).
  • Therefore jq interprets --argjson -v 2 as a number, and comparison .ID == $v works as intended (note that the same applies to --argjson -v '2' / --argjson -v "2", where the shell removes the quotes before jq sees the value).
    By contrast, anything you pass with --arg is always a string value that is used as-is.

  • In other words: --argjson, whose purpose is to accept arbitrary JSON texts as strings (such as '{ "ID": 2 }' in the example above), can also be used to pass number-string scalars to force their interpretation as numbers.
    The same technique also works with Boolean strings true and false.


Tip of the hat to peak for his help.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...